I just migrated an application from Spring Boot 1.x to 2.1. One of my test is failing due to a change to bean overriding default.

I tried to set spring.main.allow-bean-definition-overriding to true but it's not working. I managed to make it work by using a standalone @TestConfiguration class that I import. But if it's nested, it does not work.

You can reproduce the issue with the following classes:

@Configuration
public class ClockConfig {
    @Bean
    public Clock clock() {
        return Clock.systemUTC();
    }
}
@Service
public class MyService {
    private final Clock clock;
    public MyService(Clock clock) {
        this.clock = clock;
    }
    public Instant now() {
        return clock.instant();
    }
}
@RestController
public class MyResource {
    private final MyService myService;
    public MyResource(MyService myService) {
        this.myService = myService;
    }
    @GetMapping
    public ResponseEntity<Instant> now() {
        return ResponseEntity.ok(myService.now());
    }
}

The failing test. The clock() method is never called with Spring Boot 2.1 whereas it was with Spring Boot 1.5 or Spring Boot 2.0.

@RunWith(SpringRunner.class)
@WebMvcTest(MyResource.class)
@ContextConfiguration(classes = MyService.class)
public class ResourceTest {
    @Autowired
    private MockMvc mvc;
    @Test
    public void test() {
    }
    @TestConfiguration
    static class TestConfig {
        @Bean
        public Clock clock() {
            return Clock.fixed(Instant.MIN, ZoneId.of("Z"));
        }
    }
}

Comment From: snicoll

@sydneyhenrard thanks for reporting an upgrade problem. Using @ContextConfiguration is quite unusual (if you want to import an additional configuration class for your test, just use @Import). I am not sure I get a full picture of the problem and code in text is not very useful I am afraid. Please share an actual sample (github or zip) we can run ourselves.

Comment From: sydneyhenrard

@snicoll The reason I used @ContextConfiguration is because I need a service that is not loaded by @WebMvcTest. As you said I can use @Import, I always thought it was only for @Configuration.

javadoc of @Import
Indicates one or more @Configuration classes to import.

javadoc of @ContextConfiguration
@ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.

I think it makes sense not to use @ContextConfiguration in my case because a slice test is not really an integration test.

Anyway I just reported the issue because it was working in previous versions. I created a project with the issue: https://github.com/sydneyhenrard/spring-boot-17830

Comment From: snicoll

Anyway I just reported the issue because it was working in previous versions.

As I've already indicated, we appreciate you reporting an upgrade problem. I understand that things are working as expected with @Import. Thanks for the sample, I'll have a look to it and see whether this was expected as part of an upgrade to Spring Boot 2. If it is, something is missing from the migration guide as I haven't found anything related. We'll upgrade the migration guide accordingly. Thanks again.

Comment From: sgflt

I have run into this issue too after splitting big app into modules as suggested in Structuring and Testing Modules and Layers with Spring Boot

In previous monolith there some test cases had nested static class annotated by @TestConfiguration, that provided Bean EmbeddedDatasource with database manually crafted from sql scripts. After splitting app into modules there are two types of errors. Spring boot version is unchanged: v2.2.6.RELEASE.

1) org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'setUp' defined in class path resource. This error is caused by @ComponentScan in module that scans multiple nested static classes each containing definition of specific datasource.

If I rearrange code to avoid ComponentScan. The second problem arrises.

2) org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type. Which complains about missing dependency in production code which is obviously not found because in module there is no ComponentScan nor SpringBootApplication.

Is there any possible solution to this situation? Respectively to preserve behavior of nested static classes in test case and test code still be able to access to production code.

Code example to better understanding:

@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class TestCase {
  ...
  @TestConfiguration
  static class EmbeddedDatabaseConfiguration {
    @Bean
    @Primary
    DataSource setUp() {
     // datasource with custom data
      ...
    }
}


@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class AnotherTestCase {
  ...
  @TestConfiguration
  static class EmbeddedDatabaseConfiguration {
    @Bean
    @Primary
   // this is in conflict with TestCase.EmbeddedDatabaseConfiguration after modularisation
    DataSource setUp() {
     // datasource with custom data
      ...
    }
}

Maybe it is for another issue, because my TestConfiguration is found and called, but the bean created is global and each test therefore can not mock it's own implementation. TestConfigurations in single module app are behaving as expected.

Comment From: rvervaek

I am experiencing the same issue in SB Test 2.2.13.RELEASE.

Comment From: rvervaek

I just discovered that the bean I was trying to override in my TestConfiguration is declared in another library in an AutoConfiguration class. Therefor just using @Import in my SpringBootTest didn't work, but using @ImportAutoConfiguration does.

Comment From: mbhave

I ran the original sample and the tests which use @Import instead of @ContextConfiguration pass. I am going to close this issue because as @snicoll suggested using @ContextConfiguration in slice tests is quite unusual.

@sgflt The issue you've described might be slightly different because it does not involve @ContextConfiguration. If you think you've found a bug, please open another issue with a minimal sample that we can run to reproduce it.