Hi,
I have a test class annotated with @SpringBootTest that uses a static inner @TestConfigurationclass to override a bean in the application context:
@SpringBootTest
class DefaultHelloServiceTest {
@TestConfiguration
static class MyTestConfiguration {
@Bean
@Primary
HelloService helloService() {
var helloService = new HelloService("Spring");
return helloService;
}
}
// ...
}
In Spring Boot 3.5.x MyTestConfiguration is evaluated even for tests in my test class, that are @Nested JUnit test classes:
@SpringBootTest
class DefaultHelloServiceTest {
// ... as above
@Nested
class TestBean {
@Test
void test_bean_nested() {
// ✅ WORKS in Spring Boot 3.5.x
// helloService is from MyTestConfiguration
assertEquals("Spring", helloService.getGreeting());
}
}
}
In Spring Boot 4 this does not work anymore. The MyTestConfiguration.helloService-Method is only called when a test method is executed, that is not inside a @Nested test class. Instead of my customized service the "normal" one from the application context is injected.
(When adding an explicit @Import(DefaultHelloServiceTest.MyTestConfiguration.class) to the test class, it also works in both Spring Boot versions)
I have created a repository with two simple projects (3.5.7 and 4.0.0) that reproduces the behaviour.
The two test classes: - Spring Boot 4: https://github.com/nilshartmann/spring-testconfiguration-example/blob/main/spring-boot-4/src/test/java/nh/demo/testconfiguration/domain/DefaultHelloServiceTest.java - Spring Boot 3.5.7: https://github.com/nilshartmann/spring-testconfiguration-example/blob/main/spring-boot-3/src/test/java/nh/demo/testconfiguration/domain/DefaultHelloServiceTest.java
Not sure what the correct behaviour is and if I'm doing something wrong here, but for me it seems, that the behaviour has changed.
Comment From: snicoll
Thanks for the report and the samples. It looks like we may need to adapt to something that has changed in Spring Framework.
Comment From: nilshartmann
@snicoll Sorry, hadn't read that document. When adding @SpringExtensionConfig(useTestClassScopedExtensionContext = true) it works. Not sure what that exactly means though 🥺
Comment From: snicoll
Thanks for testing @nilshartmann - This probably confirms that our integration test infrastructure has to adapt to the code change from Framework.
Comment From: sbrannen
When adding
@SpringExtensionConfig(useTestClassScopedExtensionContext = true)it works.
As a side note, if you additionally annotate DefaultHelloServiceTest with an empty @ContextConfiguration declaration it should work without @SpringExtensionConfig(useTestClassScopedExtensionContext = true).
So, please let me know if that works for you.
Furthermore, I was able to reproduce this without Spring Boot involved. So, I'll investigate this in Spring Framework.
Comment From: sbrannen
As a side note, if you additionally annotate
DefaultHelloServiceTestwith an empty@ContextConfigurationdeclaration it should work without@SpringExtensionConfig(useTestClassScopedExtensionContext = true).So, please let me know if that works for you.
Please note that the above is only a potential workaround.
It might not work for more involved use cases with Spring Boot's testing support.
Comment From: nilshartmann
Hi @sbrannen! Thanks for investigating. Adding @ContextConfiguration make the test working.
So I see now three different options that make the test working:
@Import(DefaultHelloServiceTest.MyTestConfiguration.class)
// or
@SpringExtensionConfig(useTestClassScopedExtensionContext = true)
// or
@ContextConfiguration
class DefaultHelloServiceTest { /* ... */ }