如何在JUnit Jupiter ExecutionCondition中注入Spring Bean并解决实例化异常
解决JUnit 5 @ExtendWith结合Spring Bean的问题
问题根源
你遇到的NoSuchMethodException是因为JUnit 5的Extension(比如你实现的ExecutionCondition)如果直接通过@ExtendWith指定类,JUnit会尝试用无参构造函数实例化它,但你的PlatformExecutionCondition用了@RequiredArgsConstructor,没有生成无参构造;更关键的是,JUnit的实例化流程不会走Spring容器,所以你依赖的EmulatorConfigProperties和PlatformAnnotationManager根本没法注入。
正确实现方式
要让自定义Condition结合Spring使用,核心是让Extension能获取到Spring容器中的Bean,而不是让JUnit直接实例化你的Condition类。
方案1:通过SpringExtension委托调用Spring管理的Condition
- 调整你的
PlatformExecutionCondition:保留@Component和@RequiredArgsConstructor,确保它是Spring容器管理的Bean,正常实现ExecutionCondition接口:
@Component @RequiredArgsConstructor public class PlatformExecutionCondition implements ExecutionCondition { private final EmulatorConfigProperties emulatorConfig; private final PlatformAnnotationManager platformAnnotationManager; @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { // 你的原有逻辑实现 // ... } }
- 创建Spring感知的代理Extension:这个Extension负责从Spring容器中取出你的Condition实例,然后委托执行逻辑:
public class SpringPlatformExtension implements ExecutionCondition { @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { // 通过SpringExtension获取当前测试的Spring上下文 ApplicationContext ctx = SpringExtension.getApplicationContext(context); // 从容器中取出你的Condition Bean PlatformExecutionCondition condition = ctx.getBean(PlatformExecutionCondition.class); // 委托执行原有逻辑 return condition.evaluateExecutionCondition(context); } }
- 配置测试类:测试类上使用
@SpringJUnitConfig(Spring Boot项目用@SpringBootTest)启动Spring容器,同时用@ExtendWith指定代理的Extension:
@SpringJUnitConfig(classes = {你的配置类.class}) @ExtendWith(SpringPlatformExtension.class) @Platform // 你的自定义注解 public class YourTest { // 测试方法 }
方案2:在Condition内部直接获取Spring上下文(简化版)
如果不想写代理类,可以直接在PlatformExecutionCondition中通过SpringExtension获取上下文,去掉构造注入,改为从容器中取Bean:
public class PlatformExecutionCondition implements ExecutionCondition { @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { ApplicationContext ctx = SpringExtension.getApplicationContext(context); EmulatorConfigProperties emulatorConfig = ctx.getBean(EmulatorConfigProperties.class); PlatformAnnotationManager platformAnnotationManager = ctx.getBean(PlatformAnnotationManager.class); // 你的原有逻辑实现 // ... } }
然后测试类上同时加@SpringJUnitConfig(或@SpringBootTest)和@ExtendWith(PlatformExecutionCondition.class)即可。这种方式不需要把Condition注册为Spring Bean,但逻辑上把依赖获取嵌入到了Condition方法中。
关键注意点
- 必须用
@SpringJUnitConfig或@SpringBootTest来启动Spring容器,这两个注解已经包含了@ExtendWith(SpringExtension.class),是Spring和JUnit整合的基础。 - 不要让JUnit直接实例化依赖Spring Bean的Extension,必须通过Spring容器获取实例或依赖。
内容的提问来源于stack exchange,提问作者Fimoknat
相关产品推荐
相关产品推荐

