'Integration testing using @SpringBootTest is not picking auto-configuration of library configured using spring.factories
We have a library ,in order to auto-configure the library we use spring.factories file under(src/main/resources/META-INF
) which provides classes to auto-configure my library.
Reference : https://docs.spring.io/spring-boot/docs/1.4.0.M3/reference/htmlsingle/#boot-features-custom-starter
I have below configuration in spring.factories file :
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.x.y.PubSubConfig
My understanding is spring.factories is an alternative to configure library and server purpose similar to @SpringBootApplication
in a normal application.
I am doing integration using using @SpringBootTest
, I expect my context to be configured from configuration classes provided by spring.factories. When i run these tests spring does not identify spring.factories and throws an error
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
- If i annotate my
PubSubConfig
with SpringBootApplication then my integration tests run perfectly fine but since it is a library I don't wanna do so. - If I provide my configuration class specifically using
@SpringBootTest(classes = PubSubConfig.class)
my tests run fine.
Now I am trying to understand why I need to do either of above dedicatedly as spring.factories is responsible to do my auto-configure
Solution 1:[1]
@SpringBootTest
is designed for testing a Spring Boot application. Without any other configuration it looks for a class annotated or meta-annotated with @SpringBootConfiguration
. Typically this is your application's main class that is annotated with @SpringBootApplication
(which it meta-annotated with @SpringBootConfiguration
. @SpringBootApplication
is also meta-annotated with @EnableAutoConfiguration
so when @SpringBootTest
finds the @SpringBootApplication
-annotated class auto-configuration is enabled for the tests as it would be when the application itself is being executed.
When you're trying to test your auto-configuration, there's no class annotated with @SpringBootConfiguration
so you see this failure:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
As you've noted, you could fix the problem by annotating PubSubConfig
with @SpringBootApplication
but you should not do that as it's a library. @SpringBootTest(classes=PubSubConfig.class)
is a better solution as it avoids changing your library's main code, however it's still not ideal as @SpringBootTest
is really aimed at testing a Spring Boot application rather than a library that's intended for use within a Spring Boot application.
Rather than using @SpringBootTest
, I would recommend using ApplicationContextRunner
instead. As it name suggests, it's designed for running an application context. It provides builder methods for configuration auto-configuration and user-configuration that should be used to create the context, setting properties, etc. It also provides an assertable application context that allows you to easily check that the expected beans have and have not been defined. It's used extensively in Spring Boot's own tests for its auto-configuration.
Here's an example taken from Spring Boot's own tests for its DataSource
auto-configuration:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
.withPropertyValues("spring.datasource.initialization-mode=never",
"spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt());
@Test
public void testDefaultDataSourceExists() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DataSource.class));
}
Solution 2:[2]
In any Spring Boot auto-configuration issue I recommend adding debug: true
property to application.yaml
. This causes extra debug logs showing which auto-configuration classes were picked up (having criteria that matched) and which were not. In the latter case it shows what conditions didn't match.
Here is a good article about this: https://www.baeldung.com/spring-boot-auto-configuration-report
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Andy Wilkinson |
Solution 2 | Krzysztof Tomaszewski |