Search code examples
javaspring-bootthymeleafjunit5spring-test

How to unit test a Thymeleaf template using Spring Boot Test


I am parsing a Thymeleaf template using the following bean:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

@Service
public class ThymeleafProcessor {

    private final TemplateEngine templateEngine;

    @Autowired
    public ThymeleafProcessor(TemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }

    public String process() {
        final var templateResolvers = templateEngine.getTemplateResolvers();
        System.out.println(templateResolvers);// Collection with one SpringResourceTemplateResolver 
        String process = templateEngine.process("test.html", new Context());
        System.out.println(process); //Prints "Hello World"
        return process;
    }
}

The template is located in src/main/resources/templates and looks like this:

Hello World

So far everything works fine.

Now I want to write a unit test for the bean but this doesn't work:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.thymeleaf.TemplateEngine;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {
        ThymeleafProcessor.class,
        TemplateEngine.class,
})
@EnableConfigurationProperties
class ThymeleafProcessorTest {

    @Autowired
    private ThymeleafProcessor thymeleafProcessor;

    @Autowired
    private TemplateEngine templateEngine;


    @Test
    void doTest() {
        System.out.println(templateEngine.getTemplateResolvers().size());  //this will return 0 in the test

        var result = thymeleafProcessor.process();

        assertEquals("Hello World", result);
    }

}

Insetad of the expected String "Hello World" the String "test.html" is returned. The problem seems to be that no Template Resolver is available.

How does the test need to be configured in order to test the Thymeleaf template?


Solution

  • Those thymeleaf related beans are auto-configured by ThymeleafAutoConfiguration which is enabled if any configuration class is annotated with @EnableAutoConfiguration.

    @SpringBootApplication has this @EnableAutoConfiguration , so when you start the app in normal way , ThymeleafAutoConfiguration takes effect and define the related thymeleaf beans.

    But now in test , you just specify to use ThymeleafProcessor and TemplateEngine as the configuration class to start the spring context. Neither @SpringBootApplication nor @EnableAutoConfiguration involved and so ThymeleafAutoConfiguration does not take effect.

    You can fix it by explicitly import ThymeleafAutoConfiguration using @ImportAutoConfiguration :

    @SpringBootTest(classes = {ThymeleafProcessor.class})
    @ImportAutoConfiguration(ThymeleafAutoConfiguration.class)
    class ThymeleafProcessorTest {
    
    
    }
    

    I also tidy up the codes a bit :

    • @ExtendWith(SpringExtension.class) is not required as it is already defined by @SpringBootTest

    • Do not need to define TemplateEngine in @SpringBootTest as it will be defined by ThymeleafAutoConfiguration

    • Most probably @EnableConfigurationProperties is also not required.