联合 github/junit5-samples-extensions 简略阐明 @ExtendWith 的底层执行流程。
代码
@ExtendWith(RandomParametersExtension.class)
class RandomParametersExtensionTests {
@Test
void injectsInteger(@Random int i, @Random int j) {assertNotEquals(i, j);
}
}
public class RandomParametersExtension implements ParameterResolver {@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Random { }
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {return parameterContext.isAnnotated(Random.class);
}
@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {return getRandomValue(parameterContext.getParameter(), extensionContext);
}
private Object getRandomValue(Parameter parameter, ExtensionContext extensionContext) {Class<?> type = parameter.getType();
java.util.Random random = extensionContext.getRoot().getStore(Namespace.GLOBAL)//
.getOrComputeIfAbsent(java.util.Random.class);
if (int.class.equals(type)) {return random.nextInt();
}
if (double.class.equals(type)) {return random.nextDouble();
}
throw new ParameterResolutionException("No random generator implemented for" + type);
}
}
执行流程
- 在 intellij 里执行 test
1 如果是 maven 我的项目,执行 intellij-rj 里的一个 main 办法
2 如果是 gradle,是间接 gradle 的 main 办法。 - 调用 junit-platform-launcher 的入口。
- 创立 NodeTestTask。
- 依据 junit 的配置,抉择 executorService,默认单线程,配置到 NodeTestTask。
- 创立 ClassBasedTestDescriptor , 用来形容测试类 RandomParametersExtensionTests。
- ClassBasedTestDescriptor 调用 prepare 办法,扫描测试类、参数、办法上所有的注解,比方类的 @extendWith,办法上的 @BeforeALl 等。@extendWith 润饰的 extendsion 放到 extendsionRegistry,@BeforeALl 润饰的独自放到对应 List<Method> 里。(@extendWith 是 junit 预留的扩张类入口)
到这里,就实现了注解的扫描。 - 创立 TestMethodTestDescriptor,用来形容测试方法 injectsInteger()
- TestMethodTestDescriptor 调用 execute 办法,顺次触发 @BeforeEach 等形容的办法,而后调用理论的 invokeMethod,而后再登程 @BeforeAfter 等形容的办法。
-
invokeMethod 办法,先调用 resolveParameters 办法
- 扫描 extendsionRegistry 里的实现 ParameterReslolver 接口的 extendsion,这里就是 RandomParametersExtension 类。(ParameterReslolver 接口是 junit 预留的参数解析的入口 )
-
RandomParametersExtension 调用 resolveParameters 办法
- 先调用 supportParameter, 查看 method 是否反对这个 Extension,这里是通过参数上 @Random 判断。
- 调用 resolveParameter, 设置办法的 argument。
到这里,就实现了参数的解析。
- invokeMethod 办法,理论调用 invke 办法,通过 reflect 调用 native 办法,理论触发测试方法。
到这里,就实现了整个测试方法的执行过程。