How to integration test auto configuration for a custom Spring Boot style starter library?
Asked Answered
C

2

11

I am writing a library to provide some functionality that is shared between multiple different Spring Boot applications that I work with.

I would like to do something similar to the auto-configuration that is provided by the many Spring Boot starter libraries exist. That, or some other simple declarative way to integrate my library with the ApplicationContext of the apps using it.

I have found some resources explaining how auto configuration works. I can figure out the above problem.

However, I have not been able to find any good examples of how I can test as part of my library's test suite that it suitably integrates with a Spring Boot application. Ideally, I would start up a simple Spring Boot app written in the library's test directly just for the sake of testing, add the right annotation to it, and be able to assert that the correct beans are then configured.

I have tried creating a TestApplication class that does that and writing integration tests using the SpringBootTest annotation but the TestApplication was never started before my test started.

What can I do to start up a simple app like that solely for the purpose of testing my library? My tests are written with Spock and Spock-Spring in case that changes things versus other test frameworks.

Christos answered 28/3, 2017 at 19:19 Comment(0)
C
11

I was able to make it work with the following test class:

@SpringBootTest
@ContextConfiguration(classes = TestApplication)
class DummyIntegrationSpec extends Specification {

    @Autowired
    DummyService dummyService

    void 'dummy service should exist'() {
        expect:
        dummyService.getMessage() == DummyConfiguration.MESSAGE
    }
}

and this TestApplication class at src/test/groovy/com/example/project/TestApplication.groovy

@SpringBootApplication(scanBasePackages = 'com.example.project.config')
@EnableAutoConfiguration
class TestApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(TestApplication)
    }

    static void main(String[] args) {
        SpringApplication.run(TestApplication, args)
    }
}

The two key changes I had to make in order for the TestApplication to start and load the correct context when I moved my TestApplication class from src/main to src/test were:

  • the TestApplication class needed to be added to the ContextConfiguration annotation

  • the package that my library's Java config files live in needed to be added to the SpringBootApplication scanBasePackages field

The library auto-configuration does follow a similar structure to the one mentioned in the link tom provided.

Christos answered 4/4, 2017 at 16:0 Comment(1)
I don't think that this approach tests the auto-configuration, but instead just loads the @Configuration annotated class like it would without any auto-configuration spring.factories...Countrywoman
B
3

Your auto-configuration should be automatically picked while your main spring application/test is starting and all beans will be registered in your context. They will be available for auto-wiring and follow your conditions and init order.

As a summary, make sure you have an auto-configuration annotated by @Configuration class with an @Import that imports your @Configuration annotated configuration classes (inside of them you define beans with methods annotated with @Bean). Also make sure you created a spring.factories file that include your auto-configuration class and that you removed the spring boot maven plugin (for the packaging to be right).

Also, make sure your auto-configuration project is NOT annotated by things like @SpringBootApplication, @EnableAutoConfiguration, @ComponentScan or other spring boot annotations that need to be only in the main spring boot projects (There should be one of them in each stack).

Please also see the article below:


Spring boot is based on a lot of pre-made auto-configuration parent projects. You should already be familiar with spring boot starter projects.

You can easily create your own starter project by doing the following easy steps:

  1. Create some @Configuration classes to define default beans. You should use external properties as much as possible to allow customization and try to use auto-configuration helper annotations like @AutoConfigureBefore, @AutoConfigureAfter, @ConditionalOnBean, @ConditionalOnMissingBean etc. You can find more detailed information on each annotation in the official documentation Condition annotations

  2. Place an auto-configuration file/files that aggregates all of the @Configuration classes.

  3. Create a file named spring.factories and place it in src/main/resources/META-INF.

  4. In spring.factories, set org.springframework.boot.autoconfigure.EnableAutoConfiguration property with comma separated values of your @Configuration classes:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.mycorp.libx.autoconfigure.LibXAutoConfiguration,
    com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration Using this method you can create your own auto-configuration classes that will be picked by spring-boot. Spring-boot automatically scan all maven/gradle dependencies for a spring.factories file, if it finds one, it adds all @Configuration classes specified in it to its auto-configuration process.

Make sure your auto-configuration starter project does not contain spring boot maven plugin because it will package the project as an executable JAR and won't be loaded by the classpath as intended - spring boot will not be able to find your spring.factories and won't load your configuration

Badtempered answered 29/3, 2017 at 7:2 Comment(3)
That's helpful for creating the auto configuration, but not exactly the question I am asking. The question I am asking is, how can I integration test my auto-configuration with a test Spring Boot application.Christos
As i mentioned, once the auto-configuration is in place all your beans are loaded to your context and you can inject your beans (components/services/repositories etc) in order to test them in your test classesBadtempered
That works just fine when the Application class is under src/main. The Application class is run and all the beans are configured as expected. If I move the same Application class to src/test, the Application doesn't start at all. No beans are instantiated. The behavior is the same whether the test is using @ ContextConfiguration or the @ SpringBootTest annotation classes field refers to the Application class.Christos

© 2022 - 2024 — McMap. All rights reserved.