如何测试@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属性不存在时,someClassBean不创建 - 测试当已有
someClassBean时,自动配置的Bean不重复创建 - 测试当
KeyStoreBean不存在时,someClassBean不创建
内容的提问来源于stack exchange,提问作者unknown
相关产品推荐
相关产品推荐

