当前位置: 首页 > 后端技术 > Java

《底层到底做了什么》---junit5的@ExtendWith

时间:2023-04-01 19:51:39 Java

结合github/junit5-samples-extensions,简单说明一下@ExtendWith的底层执行流程。代码@ExtendWith(RandomParametersExtension.class)classRandomParametersExtensionTests{@TestvoidinjectsInteger(@Randominti,@Randomintj){assertNotEquals(i,j);}}公共类RandomParametersExtension实现ParameterResolver{@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public@interfaceRandom{}@OverridepublicbooleansupportsParameter(ParameterContextparameterContext,ExtensionContextextensionContext){returnparameterContext.isAnnotated(Random.class);}@OverridepublicObjectresolveParameter(ParameterContextparameterContext,ExtensionContextextensionContext){returngetRandomValue(parameterContext.getParameter(),extensionContext);}privateObjectgetRandomValue(Parameterparameter,ExtensionContextextensionContext){Classtype=parameter.getType();java.util.Random随机=extensionContext.getRoot().getStore(Namespace.GLOBAL)//.getOrComputeIfAbsent(java.util.Random.class);如果(int.class.equals(type)){返回random.nextInt();}if(double.class.equals(type)){returnrandom.nextDouble();}thrownewParameterResolutionException("Norandomgeneratorimplementedfor"+type);}}时序图【图】执行流程在intellij中执行test1如果是maven工程,在intellij-rj中执行一个main方法2如果是gradle,则是直接从main调用junit-platform-launcher的入口gradle的方法。创建一个NodeTestTask。根据junit的配置,选择executorService,默认单线程,配置为NodeTestTask。创建一个ClassBasedTestDescriptor来描述测试类RandomParametersExtensionTests。ClassBasedTestDescriptor调用prepare方法扫描测试类、参数、方法上的所有注解,比如类上的@extendWith,方法上的@BeforeALLl等。@extendWith修饰的extension放在extensionRegistry中,一个@BeforeALLl修改的放在对应的List中。(@extendWith是junit保留的扩展类入口)至此,对注解的扫描就完成了。创建TestMethodTestDescriptor描述测试方法injectsInteger()TestMethodTestDescriptor调用execute方法,依次触发@BeforeEach描述的方法,然后调用实际的invokeMethod,然后启动@BeforeAfter描述的方法。invokeMethod方法首先调用resolveParameters方法扫描实现了ParameterReslolver接口的extensionRegistry中的extension,这里是RandomParametersExtension类。(ParameterReslolver接口是junit保留的参数解析入口)RandomParametersExtension调用resolveParameters方法首先调用supportParameter检查该方法是否支持该Extension,通过参数上的@Random判断。调用resolveParameter来设置方法的参数。至此,参数的解析就完成了。invokeMethod方法实际上调用了invke方法,通过reflect调用了native方法,真正触发了test方法。至此,整个测试方法的执行过程就完成了。