Home > Back-end >  BeanDefinitionOverrideException when supplying bean for integration test / @SpringBootTest
BeanDefinitionOverrideException when supplying bean for integration test / @SpringBootTest

Time:10-31

I configure a Clock bean like this:

@Configuration
public class ClockConfiguration {

    @Bean
    Clock clock() {
        return Clock.systemDefaultZone();
    }
}

For an integration test, however, I need a Clock instance with a fixed time, so I added a static @TestConfiguration like this:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = WireMockInitializer.class)
@AutoConfigureWebTestClient
@ActiveProfiles("test")
class MyIT {

    @TestConfiguration
    static class ClockTestConfiguration {

        @Bean
        public Clock clock() {
            return Clock.fixed(Instant.ofEpochMilli(1635513004000L), ZoneId.systemDefault());
        }
    }

    @Autowired
    WireMockServer wireMockServer;

    @Autowired
    private WebTestClient webTestClient;

    @AfterEach
    void afterEach() {
        wireMockServer.resetAll();
    }

    @Test
    void testFoo() {}
}

But when running the test, the application context cannot be loaded. Instead, this error message is shown:

org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'clock' defined in de.myapp.MyIT$ClockTestConfiguration

There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=clockConfiguration; factoryMethodName=clock; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [de/myapp/ClockConfiguration.class]] bound.

My understanding was that the static @TestConfiguration would actually take care of that?

CodePudding user response:

From Spring boot 2.0 and upwards, you have to enable bean overriding in application.yml to allow Spring to override the instance of Clock from the actual application with the one in you want in integration test:

spring:
  main:
    allow-bean-definition-overriding: true

CodePudding user response:

It seems that several workarounds will be available.

1: Set spring.main.allow-bean-definition-overriding=true on src/test/resources/application.properties(or on application-test.properties; you activate test profile) .

2: If @Qualifier is not specified on auto-wiring, define test bean as @Primary with different bean name:

    @TestConfiguration
    static class ClockTestConfiguration {

        @Bean("fixedClock")
        @Primary
        public Clock clock() {
            return Clock.fixed(Instant.ofEpochMilli(1635513004000L), ZoneId.systemDefault());
        }
    }

See also:

  • Related