BeanDefinitionOverrideException 为集成测试提供 bean / @SpringBootTest

BeanDefinitionOverrideException when supplying bean for integration test / @SpringBootTest

我这样配置 Clock bean:

@Configuration
public class ClockConfiguration {

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

但是,对于集成测试,我需要一个具有固定时间的 Clock 实例,所以我添加了一个静态 @TestConfiguration,如下所示:

@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() {}
}

但是运行测试时,无法加载应用上下文。相反,显示此错误消息:

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.

我的理解是静态 @TestConfiguration 实际上会解决这个问题?

从 Spring boot 2.0 及更高版本开始,您必须在 application.yml 中启用 bean 覆盖,以允许 Spring 从实际应用程序中覆盖 Clock 的实例在集成测试中你想要的那个:

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

似乎有几种解决方法。

1: 在 src/test/resources/application.properties 上设置 spring.main.allow-bean-definition-overriding=true(或在 application-test.properties 上;您激活 test 配置文件)。

2: 如果@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());
        }
    }

另请参阅: