联合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);    }}

执行流程

  1. 在intellij里执行test
    1 如果是maven我的项目,执行intellij-rj里的一个main办法
    2 如果是gradle,是间接gradle的main办法。
  2. 调用junit-platform-launcher的入口。
  3. 创立NodeTestTask。
  4. 依据junit的配置,抉择executorService,默认单线程,配置到NodeTestTask。
  5. 创立 ClassBasedTestDescriptor ,用来形容测试类RandomParametersExtensionTests。
  6. ClassBasedTestDescriptor调用prepare办法,扫描测试类、参数、办法上所有的注解,比方类的@extendWith,办法上的@BeforeALl等。@extendWith润饰的extendsion放到extendsionRegistry,@BeforeALl润饰的独自放到对应List<Method>里。(@extendWith是junit预留的扩张类入口)
    到这里,就实现了注解的扫描。
  7. 创立TestMethodTestDescriptor,用来形容测试方法 injectsInteger()
  8. TestMethodTestDescriptor调用execute办法,顺次触发@BeforeEach等形容的办法,而后调用理论的invokeMethod,而后再登程@BeforeAfter等形容的办法。
  9. invokeMethod办法,先调用resolveParameters办法

    1. 扫描extendsionRegistry里的实现ParameterReslolver接口的extendsion,这里就是RandomParametersExtension类。(ParameterReslolver接口是junit预留的参数解析的入口
    2. RandomParametersExtension调用resolveParameters办法

      1. 先调用supportParameter,查看method是否反对这个Extension,这里是通过参数上@Random判断。
      2. 调用resolveParameter,设置办法的argument。

    到这里,就实现了参数的解析。

  10. invokeMethod办法,理论调用invke办法,通过reflect调用native办法,理论触发测试方法。
    到这里,就实现了整个测试方法的执行过程。