如何在JUnit 5中实现依赖注入?多对象注入及TestInfo的疑问
关于JUnit 5依赖注入(DI)的问题解答
一、你对DI的核心理解是对的,但实现方式需要调整
你认为DI是给测试提供不同对象变体来执行的思路没问题,但直接像你写的那样定义测试方法参数,JUnit 5不会自动识别并注入Class1/Class2/Class3的实例。要实现这种多对象变体的测试,你需要结合JUnit 5的参数化测试或者自定义扩展来完成:
1. 用参数化测试实现多对象变体测试
如果只是想让同一个测试逻辑跑不同的Base子类实例,最直接的方式是用@ParameterizedTest配合@MethodSource:
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.*; public class BaseTest { // 提供不同的Base实例数据源 static Base[] baseInstances() { return new Base[]{new Class1(), new Class2(), new Class3()}; } @ParameterizedTest @MethodSource("baseInstances") void myTest(Base baseObj) { // 你的断言逻辑 assertNotNull(baseObj); assertTrue(baseObj instanceof Base); } static class Base {} static class Class1 extends Base {} static class Class2 extends Base {} static class Class3 extends Base {} }
这样JUnit会自动遍历baseInstances()返回的每个实例,分别执行myTest方法。
2. 用自定义扩展实现DI注入
如果需要更灵活的注入逻辑(比如根据测试标签、上下文动态提供实例),可以自定义Extension:
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterResolver; import java.lang.reflect.Parameter; public class BaseInstanceResolver implements ParameterResolver { @Override public boolean supportsParameter(Parameter parameter, ExtensionContext context) { // 只处理Base类型的参数 return parameter.getType().isAssignableFrom(Base.class); } @Override public Object resolveParameter(Parameter parameter, ExtensionContext context) { // 这里可以根据测试上下文返回不同的实例,比如根据测试方法名 String testMethodName = context.getRequiredTestMethod().getName(); if ("testClass1".equals(testMethodName)) { return new Class1(); } else if ("testClass2".equals(testMethodName)) { return new Class2(); } return new Class3(); } }
然后在测试类上标注@ExtendWith(BaseInstanceResolver.class),就可以在测试方法中直接注入Base类型的参数了:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(BaseInstanceResolver.class) public class BaseDI { @Test void testClass1(Base baseObj) { assertTrue(baseObj instanceof Class1); } @Test void testClass2(Base baseObj) { assertTrue(baseObj instanceof Class2); } // 其他测试类定义... }
二、TestInfo类的作用(和你要的DI不是一回事)
TestInfo是JUnit 5内置的元信息工具类,它的作用是让你获取当前测试的元数据,比如测试方法名、显示名称、标签等,和多对象变体的DI没有直接关系。举个例子:
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; public class TestInfoExample { @Test @DisplayName("测试Class1实例") void testWithTestInfo(TestInfo testInfo) { // 获取测试方法名 System.out.println("当前测试方法:" + testInfo.getTestMethod().get().getName()); // 获取显示名称 System.out.println("测试显示名:" + testInfo.getDisplayName()); // 可以根据这些信息做一些动态逻辑,比如不同测试打不同日志 } }
简单说,TestInfo是帮你了解当前测试的“身份信息”,而不是用来提供业务对象的。你要的多对象注入,还是得用前面说的参数化测试或者自定义扩展来实现。
内容的提问来源于stack exchange,提问作者TalClip
相关产品推荐
相关产品推荐

