Search code examples
springspring-bootkotlindependency-injectionintegration-testing

Autowire auto-configured dependency in integration test


As part of my Spring Boot app, I have a Thymeleaf HTML template rendering service:

@Service
class TemplateService(private val templateEngine: SpringTemplateEngine) {

    fun renderTemplate(templateName: String, vars: Map<String, Any>): String =
        templateEngine.process(templateName, Context()
}

A method in this service calls templateEngine.process. I would like to test renderTemplate on a concrete template to make sure that the template is rendered properly. Now, TemplateEngine needs a resolver to render a template. Inspecting the source code I see that there's a default StringTemplateResolver if there's nothing else configured. The resolver just treats the first argument of process as a template string (instead of a template name which is what I want). Naturally then, this template resolver is used in my integration test which is set up like this:

@SpringJUnitConfig(classes = [SpringTemplateEngine::class])
class TemplateServiceIT @Autowired constructor(
    springTemplateEngine: SpringTemplateEngine,
) {
    private val templateService = TemplateService(springTemplateEngine)
}

This code "works" in the way that all the dependencies are correctly set up and I can create my TemplateService instance. However, SpringTemplateEngine is configured differently in this test than in the context of a real Spring Boot app because there an extra autoconfiguration is applied which sets up SpringResourceTemplateResolver which correctly treats templateName as a template name and not a template string.

Now to my question. I want to set up my test context in such a way that:

  • Spring injects auto-configured SpringTemplateEngine (with SpringResourceTemplateResolver)
  • I don't have to start the whole Spring Boot app with SpringBootTest

Solution

  • The correct way is to use @ImportAutoConfiguration:

    @SpringJUnitConfig(TemplateService::class)
    // This auto-configures SpringTemplateEngine
    @ImportAutoConfiguration(ThymeleafAutoConfiguration::class)
    class TemplateServiceIT @Autowired constructor(private val templateService: TemplateService) {
    
      ...tests
    }