You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@SpringBootTest集成测试替换Clock Bean报BeanDefinitionOverrideException如何解决

异常原因

Spring Boot 2.1+ 版本默认将spring.main.allow-bean-definition-overriding配置为false,禁止同名称Bean的覆盖,避免非预期的Bean替换引发线上问题。
而@TestConfiguration的核心作用是为测试场景补充额外的Bean配置,默认不会自动覆盖已存在的同名称Bean,你在测试类中定义的clock Bean和生产配置类中的clock Bean名称、类型完全一致,上下文加载时检测到重复的Bean定义,就会抛出BeanDefinitionOverrideException。

解决方案

以下方案按推荐优先级排序:

  • 方案1:给测试Bean添加@Primary注解
    在测试配置类的clock Bean上添加@Primary,Spring在存在多个同类型Bean时,会优先使用标注了@Primary的Bean,不需要修改全局配置,侵入性最低。
    代码示例:
@TestConfiguration
static class ClockTestConfiguration {
    @Bean
    @Primary
    public Clock clock() {
        return Clock.fixed(Instant.ofEpochMilli(1635513004000L), ZoneId.systemDefault());
    }
}
  • 方案2:给生产Bean指定环境排除测试场景
    在生产的Clock配置类的Bean上添加@Profile("!test"),测试环境下生产的Clock Bean不会被注册到容器中,自然不会出现冲突:
@Configuration
public class ClockConfiguration {
    @Bean
    @Profile("!test")
    Clock clock() {
        return Clock.systemDefaultZone();
    }
}
  • 方案3:开启全局Bean覆盖配置
    在application-test.properties(或yml)中添加如下配置,允许测试环境下Bean覆盖:
spring.main.allow-bean-definition-overriding=true

该方案属于全局配置,可能会引发其他非预期的Bean覆盖问题,优先级低于前两种。

  • 方案4:使用@MockBean直接替换原有Bean
    不需要额外写测试配置类,直接在测试类中声明@MockBean替换容器中原有的Clock实例,再指定返回逻辑即可:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = WireMockInitializer.class)
@AutoConfigureWebTestClient
@ActiveProfiles("test")
class MyIT {
    @MockBean
    private Clock clock;

    @BeforeEach
    void setupClock() {
        Clock fixedClock = Clock.fixed(Instant.ofEpochMilli(1635513004000L), ZoneId.systemDefault());
        Mockito.when(clock.instant()).thenReturn(fixedClock.instant());
        Mockito.when(clock.getZone()).thenReturn(fixedClock.getZone());
    }
    // 其他测试代码
}

内容的提问来源于stack exchange,提问作者Robert Strauch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 07:36:07