JUnit5扩展注册时如何注入依赖并传入测试类初始化参数
问题原因
原来的实现报错是因为:JUnit 初始化@RegisterExtension标注的扩展实例的时机,早于Spring测试框架对测试类字段的依赖注入流程,此时dataSource还未被赋值为null,自然无法正常运行。
方案1:Supplier延迟加载(最推荐,完全框架无关)
该方案无需绑定任何框架,仅依赖Java 8+的Supplier特性,适配所有测试场景,不管你用Spring还是其他依赖注入框架,甚至是手动给测试类字段赋值都可以使用,不强制依赖@Autowired。
扩展修改:
@RequiredArgsConstructor public class FakeExtension implements BeforeEachCallback { // 用Supplier包装参数,延迟到实际执行逻辑时再获取值 private final Supplier<DataSource> dataSourceSupplier; @Override public void beforeEach(ExtensionContext context) throws Exception { // 此时测试类的字段已经完成初始化/注入,可以拿到有效值 DataSource dataSource = dataSourceSupplier.get(); System.out.println("Do something with " + dataSource); } }
测试类使用:
@SpringBootTest public class FakeTest { @Autowired DataSource dataSource; // 传入lambda返回当前实例的dataSource字段 @RegisterExtension FakeExtension ext = new FakeExtension(() -> this.dataSource); @Test void test() { System.out.println("Run test"); } }
方案2:扩展内反射获取测试类字段(测试类无侵入)
如果不想修改原有扩展的入参定义,或者不想在每个测试类里编写Supplier逻辑,可以选择在扩展内部通过JUnit上下文拿到测试类实例,反射读取对应字段,同样完全不依赖Spring框架。
扩展实现:
public class FakeExtension implements BeforeEachCallback { @Override public void beforeEach(ExtensionContext context) throws Exception { // 获取当前测试类实例 Object testInstance = context.getRequiredTestInstance(); // 反射读取字段,可自定义注解标记目标字段提升通用性 Field dataSourceField = Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(f -> f.getType() == DataSource.class) .findFirst() .orElseThrow(() -> new IllegalArgumentException("测试类未定义DataSource类型字段")); dataSourceField.setAccessible(true); DataSource dataSource = (DataSource) dataSourceField.get(testInstance); System.out.println("Do something with " + dataSource); } }
测试类使用:
直接添加扩展注解即可,无需额外编码:
@SpringBootTest @ExtendWith(FakeExtension.class) public class FakeTest { @Autowired DataSource dataSource; @Test void test() { System.out.println("Run test"); } }
内容的提问来源于stack exchange,提问作者davioooh
相关产品推荐
相关产品推荐

