Description
Overview
Given the following application and test classes, the @Nested
test class fails due to getMessage()
returning "Hello!"
instead of "Mocked!"
resulting from the fact that the static nested @TestConfiguration
class is only discovered for the top-level enclosing test class.
Specifically, the MergedContextConfiguration
for TestConfigurationNestedTests
contains classes = [example.Application, example.TestConfigurationNestedTests.TestConfig]
; whereas, the MergedContextConfiguration
for InnerTests
contains only classes = [example.Application]
.
A cursory search for @TestConfiguration
reveals that SpringBootTestContextBootstrapper.containsNonTestComponent(...)
uses the INHERITED_ANNOTATIONS
search strategy for merged annotations. Instead, it should likely need to make use of TestContextAnnotationUtils
in order to provide proper support for @NestedTestConfiguration
semantics (perhaps analogous to the use of TestContextAnnotationUtils.searchEnclosingClass(...)
in MockitoContextCustomizerFactory.parseDefinitions(...)
).
As a side note, if you uncomment @Import(TestConfig.class)
both test classes will pass.
package example;
// imports...
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Service
public static class GreetingService {
public String getMessage() {
return "Hello!";
}
}
}
package example;
// imports...
@SpringBootTest
// @Import(TestConfig.class)
class TestConfigurationNestedTests {
@Test
void test(@Autowired GreetingService greetingService) {
assertThat(greetingService.getMessage()).isEqualTo("Mocked!");
}
@Nested
class InnerTests {
@Test
void test(@Autowired GreetingService greetingService) {
assertThat(greetingService.getMessage()).isEqualTo("Mocked!");
}
}
@TestConfiguration
static class TestConfig {
@MockBean
GreetingService greetingService;
@BeforeTestMethod
void configureMock(BeforeTestMethodEvent event) {
when(this.greetingService.getMessage()).thenReturn("Mocked!");
}
}
}