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

如何测试@ConditionalOnClass与@ConditionalOnBean注解的JUnit用例?

如何正确测试Spring Boot自动配置中的@Conditional系列注解

问题场景

配置类代码:

@Configuration
@ConditionalOnClass({SomeKeyService.class})
@EnableConfigurationProperties({SomeConfig.class})
public class MyServiceAutoConfig {

    @Bean
    @ConditionalOnProperty("certificate.password")
    @ConditionalOnBean(KeyStore.class)
    @ConditionalOnMissingBean
    public someClass myService(KeyStore ks, SomeConfig config) {
        return new someClass(ks, config.getPassword());
    }
}

测试类代码:

public class MyServiceAutoConfigTest{
    ApplicationRunner context = new ApplicationRunner().withConfiguration(AutoConfigurations.of(MyServiceAutoConfig.class));

    @Test
    public void givenPropertyShouldHaveSomeClassBean() {
        this.context.withUserConfiguration(MyServiceAutoConfig.class, SomeConfig.class)
            .withPropertyValues("certificate.password=hdgjashjfdjcn")
            .run((context) -> {assertThat(context).hasSingleBean(someClass.class);});
    }
}

补充说明:someClass实现了SomeKeyService,KeyStore为java.security.KeyStore。测试时出现错误:no beans found of that type。

解决方案

测试失败的核心原因是测试上下文缺少KeyStore类型的Bean,同时存在测试配置冗余问题,修正步骤如下:

1. 为测试上下文提供KeyStore Bean

配置类中的myService Bean依赖KeyStore实例,但当前测试上下文未注入该Bean,导致@ConditionalOnBean(KeyStore.class)条件不满足,Bean无法创建。可通过ApplicationRunner的withBean方法直接注入模拟实例:

this.context
    .withBean(KeyStore.class, () -> {
        try {
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(null, null);
            return ks;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    })

2. 移除冗余的测试配置

AutoConfigurations.of(MyServiceAutoConfig.class)已经将自动配置类纳入测试上下文,无需再通过withUserConfiguration重复添加MyServiceAutoConfig.class。

3. 确保SomeConfig的属性绑定生效

确认SomeConfig类上添加了@ConfigurationProperties注解,否则无法正确绑定certificate.password属性:

@ConfigurationProperties(prefix = "certificate")
public class SomeConfig {
    private String password;

    // getter、setter方法
}

修改后的完整测试类

public class MyServiceAutoConfigTest{
    ApplicationRunner context = new ApplicationRunner()
        .withConfiguration(AutoConfigurations.of(MyServiceAutoConfig.class));

    @Test
    public void givenPropertyShouldHaveSomeClassBean() {
        this.context
            .withUserConfiguration(SomeConfig.class)
            .withPropertyValues("certificate.password=hdgjashjfdjcn")
            .withBean(KeyStore.class, () -> {
                try {
                    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
                    ks.load(null, null);
                    return ks;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            })
            .run((context) -> {
                assertThat(context).hasSingleBean(someClass.class);
            });
    }
}

额外测试建议

可以补充多场景测试覆盖所有Conditional条件:

  • 测试当certificate.password属性不存在时,someClass Bean不创建
  • 测试当已有someClass Bean时,自动配置的Bean不重复创建
  • 测试当KeyStore Bean不存在时,someClass Bean不创建

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:55:15