Hi,
we've just migrated an application from boot 1.5 to 2.0 following the migration guide. Our web integration tests stopped working after migration and fail with a NoSuchBeanDefinitionException.
I know that there is a section about a semantics change regarding @ConditionalOnBean in the migration guide, but we only have one annotation in the test class so AND/OR won鈥檛 apply.
I've created a stripped-down example to reproduce the issue:
https://github.com/jwedel/conditional-on-bean-test
Run ConditionalTest as it is and it works (test green). Change the parent spring boot starter version in the pom to 2.0.3.RELEASE and it fails with the above exception.
At the core, this @Configuration class does not get loaded when running a web integration test:
@Configuration
@ConditionalOnBean(TestRestTemplate.class)
public class WebTestConfiguration {
@Bean
public WebTestObject webTestObject(TestRestTemplate testRestTemplate) {
return new WebTestObject();
}
}
Why am I doing this? We need a bean autowired only in web integration thats that needs the TestRestTemplate.
I also read an answer by @wilkinsona on StackOverflow that quotes the docs saying it will not work because @Configuration will be evaluated before auto configuration. But then I wonder why it worked on the first place.
I might be wrong, but IMO it's either a bug or a breaking change that was not documented in the migration guide...
In Spring Boot 1.5 the TestRestTemplate was registered directly but in 2.0 we intentionally defer the registration.
The reason we do this is so that a custom TestRestTemplate can be added in test auto-configuration.
Your original code was working more by accident than design I'm afraid. The @ConditionalOnBean annotation should really only be used by auto-configuration classes. See this comment in the Javadoc:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.
I'd probably recommend moving WebTestObject into your test configuration and wiring it up directly in your tests.
@philwebb Hmm, understood. So how would I have some configuration only applied to web integration tests? I worked-around it using Optional<TestRestTemplate> for now.
@jwedel You could use the classes attribute of @SpringBootTest to directly import the configuration you need.
In Spring Boot 1.5 the
TestRestTemplatewas registered directly but in 2.0 we intentionally defer the registration.
Thanks for the detailed explanation and rationale, @philwebb!
Most helpful comment
In Spring Boot 1.5 the
TestRestTemplatewas registered directly but in 2.0 we intentionally defer the registration.The reason we do this is so that a custom
TestRestTemplatecan be added in test auto-configuration.Your original code was working more by accident than design I'm afraid. The
@ConditionalOnBeanannotation should really only be used by auto-configuration classes. See this comment in the Javadoc: