JUnit 5:如何向自定义TestTemplateInvocationContextProvider注入Spring组件?
当然可以实现!在JUnit Jupiter(JUnit 5)里,要把Spring组件注入到自定义的TestTemplateInvocationContextProvider中,得绕开一点JUnit扩展的默认实例化机制——因为这类扩展默认是由JUnit自己创建的,不是Spring容器管理的,所以直接用@Autowired注解没法生效。不过我们可以通过实现ApplicationContextAware接口来拿到Spring上下文,进而获取需要的组件。
具体步骤和示例
让自定义Provider实现ApplicationContextAware接口
这个接口是Spring的核心接口之一,实现它之后,Spring会自动把当前的ApplicationContext实例传递给我们的Provider,这样我们就能通过上下文获取任意Spring管理的Bean了。同时别忘了给Provider加上@Component注解,让它成为Spring容器的一部分。import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; import java.util.stream.Stream; @Component public class CustomTestTemplateProvider implements TestTemplateInvocationContextProvider, ApplicationContextAware { private ApplicationContext applicationContext; // Spring会自动调用这个方法注入上下文 @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @Override public boolean supportsTestTemplate(ExtensionContext context) { // 根据你的需求判断是否支持当前测试模板 return true; } @Override public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) { // 在这里通过上下文获取你需要的Spring组件 MySpringService springService = applicationContext.getBean(MySpringService.class); // 比如用组件提供的数据生成测试调用上下文 return springService.getTestScenarios().stream() .map(scenario -> new TestTemplateInvocationContext() { // 实现你的上下文逻辑,比如设置参数、扩展等 }); } }在测试类中启用Spring上下文并使用Provider
测试类需要通过@SpringJUnitConfig或者@SpringBootTest来启动Spring上下文,同时用@ExtendWith指定我们的自定义Provider,或者直接在@TestTemplate注解上关联Provider。import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; // 加载包含Provider和你的Spring组件的配置类 @SpringJUnitConfig(classes = {AppConfig.class, CustomTestTemplateProvider.class}) public class MyTemplateTest { @TestTemplate @ExtendWith(CustomTestTemplateProvider.class) public void runTemplateTest(String testScenario) { // 你的测试逻辑,参数由Provider提供 System.out.println("执行测试场景: " + testScenario); } }
原理说明
JUnit Jupiter的扩展(包括TestTemplateInvocationContextProvider)默认由JUnit框架实例化,不属于Spring容器的管理范围,所以Spring无法直接通过@Autowired注入依赖。而通过实现ApplicationContextAware接口,我们借助Spring的生命周期机制,拿到了整个应用上下文的引用,这样就能手动获取任何Spring托管的组件,完美解决了注入问题。
内容的提问来源于stack exchange,提问作者gkatzioura

