SelectorResolver是一个接口,官方注释如下:
A resolver that supports resolving one or multiple types of {@link DiscoverySelector DiscoverySelectors}.An implementation of a {@code resolve()} method is typically comprised of the following steps:
Check whether the selector is applicable for the current
{@link org.junit.platform.engine.TestEngine} and the current
{@link org.junit.platform.engine.EngineDiscoveryRequest} (e.g.
for a test class: is it relevant for the current engine and does
it pass all filters in the request?).
If so, use the supplied {@link Context Context}, to add one or
multiple {@link TestDescriptor TestDescriptors} to the designated
parent (see {@link Context Context} for details) and return a
{@linkplain Resolution#match(Match) match} or multiple {@linkplain
Resolution#matches(Set) matches}.
Alternatively, convert the supplied selector into one or multiple other {@linkplain Resolution#selectors(Set) selectors} (e.g. a {@link
PackageSelector} into a set of {@link ClassSelector ClassSelectors}).
Otherwise, return {@link Resolution#unresolved() unresolved()}.
可以看到,一个解析器根据传入的不同DiscoverySelector类型,分别解析出对应的Resolution, 结果存储在Match对象SET集合中
public interface SelectorResolver {//处理ClasspathResourceSelector 选择器/*** Resolve the supplied {@link ClasspathResourceSelector} using the supplied* {@link Context Context}.*/default Resolution resolve(ClasspathResourceSelector selector, Context context) {return resolve((DiscoverySelector) selector, context);}//处理ClasspathRootSelector 选择器/*** Resolve the supplied {@link ClasspathRootSelector} using the supplied* {@link Context Context}.**/default Resolution resolve(ClasspathRootSelector selector, Context context) {return resolve((DiscoverySelector) selector, context);}//处理ClassSelector 选择器/*** Resolve the supplied {@link ClassSelector} using the supplied* {@link Context Context}.**/default Resolution resolve(ClassSelector selector, Context context) {return resolve((DiscoverySelector) selector, context);}......}class Resolution {private static final Resolution UNRESOLVED = new Resolution(emptySet(), emptySet());//解析后的Match结果集合private final Set<Match> matches;private final Set<? extends DiscoverySelector> selectors;......}class Match {//match中存放匹配的TestDescriptorprivate final TestDescriptor testDescriptor;//子选择器,从当前父DiscoverySelector到子DiscoverySelector 循环解析private final Supplier<Set<? extends DiscoverySelector>> childSelectorsSupplier;private final Type type;......}
在前面说到的discover方法里面,会调用DiscoverySelectorResolver的resolveSelectors方法解析
new DiscoverySelectorResolver().resolveSelectors(discoveryRequest, engineDescriptor);
DiscoverySelectorResolver中初始化了常用的部分解析器,其中包括ClassContainerSelectorResolver,ClassSelectorResolver和MethodSelectorResolver三个SelectorResolver和 MethodOrderingVisitor方法排序TestDescriptor.Visitor、 TestDescriptor::prune剪枝TestDescriptor.Visitor, vistor方法主要用来做后置的一些处理
public class DiscoverySelectorResolver {// @formatter:offprivate static final EngineDiscoveryRequestResolver<JupiterEngineDescriptor> resolver = EngineDiscoveryRequestResolver.<JupiterEngineDescriptor>builder().addClassContainerSelectorResolver(new IsTestClassWithTests()).addSelectorResolver(context -> new ClassSelectorResolver(context.getClassNameFilter(), context.getEngineDescriptor().getConfiguration())).addSelectorResolver(context -> new MethodSelectorResolver(context.getEngineDescriptor().getConfiguration())).addTestDescriptorVisitor(context -> new MethodOrderingVisitor(context.getEngineDescriptor().getConfiguration())).addTestDescriptorVisitor(context -> TestDescriptor::prune).build();// @formatter:onpublic void resolveSelectors(EngineDiscoveryRequest request, JupiterEngineDescriptor engineDescriptor) {resolver.resolve(request, engineDescriptor);}}
resolver.resolve方法中,直接初始化EngineDiscoveryRequestResolution对象,并执行run方法,在run方法中循环解析传入的DiscoverySelector对象和子DiscoverySelector对象,并生成Resolution结果
void run() {//获取request对象中selector选择器,即前文所描述的EngineDiscoveryRequest 对象,并加入dremainingSelectors.addAll(request.getSelectorsByType(DiscoverySelector.class));//循环处理selector队列,依次解析生成Resolution对象while (!remainingSelectors.isEmpty()) {resolveCompletely(remainingSelectors.poll());}visitors.forEach(engineDescriptor::accept);}private void resolveCompletely(DiscoverySelector selector) {try {//解析DiscoverySelector 对象Optional<Resolution> result = resolve(selector);if (result.isPresent()) {//里面会处理当前selector中包含的子selector,并放入remainingSelectors队列enqueueAdditionalSelectors(result.get());}else {//记录解析失败的selector和原因logUnresolvedSelector(selector, null);}}catch (Throwable t) {......}}
其中,调用resolve方法解析selector是关键流程,从初始化的resolvers中依次调用reslove方法,即上文所述的ClassContainerSelectorResolver,ClassSelectorResolver,MethodSelectorResolver依次处理selector,过滤isResolved的Resolution结果,把对应结果放入Map<DiscoverySelector, Resolution> resolvedSelectors中,把match结果存入Map<UniqueId, Match> resolvedUniqueIds中
在resolve(DiscoverySelector selector)方法中,会依次判断selector类型,调用对应类型的resolver去处理
private Optional<Resolution> resolve(DiscoverySelector selector,Function<SelectorResolver, Resolution> resolutionFunction) {// @formatter:offreturn resolvers.stream().map(resolutionFunction).filter(Resolution::isResolved).findFirst().map(resolution -> {contextBySelector.remove(selector);resolvedSelectors.put(selector, resolution);resolution.getMatches().forEach(match -> resolvedUniqueIds.put(match.getTestDescriptor().getUniqueId(), match));return resolution;});// @formatter:on}private Optional<Resolution> resolve(DiscoverySelector selector) {if (resolvedSelectors.containsKey(selector)) {return Optional.of(resolvedSelectors.get(selector));}if (selector instanceof UniqueIdSelector) {return resolveUniqueId((UniqueIdSelector) selector);}return resolve(selector, resolver -> {Context context = getContext(selector);if (selector instanceof ClasspathResourceSelector) {return resolver.resolve((ClasspathResourceSelector) selector, context);}//selector为ClasspathRootSelector的处理if (selector instanceof ClasspathRootSelector) {return resolver.resolve((ClasspathRootSelector) selector, context);}//selector为ClassSelector的处理if (selector instanceof ClassSelector) {return resolver.resolve((ClassSelector) selector, context);}......//selector为MethodSelector的处理if (selector instanceof MethodSelector) {return resolver.resolve((MethodSelector) selector, context);}......return resolver.resolve(selector, context);});}
public Resolution resolve(ClasspathRootSelector selector, Context context) {return classSelectors(findAllClassesInClasspathRoot(selector.getClasspathRoot(), classFilter, classNameFilter));}......//解析classPathRoot中的class即测试类,生成ClassSelectorprivate Resolution classSelectors(List<Class<?>> classes) {return selectors(classes.stream().map(DiscoverySelectors::selectClass).collect(toSet()));}
循环解析selector过程中,解析到当前seletor为ClassSelector,对应的解析器为ClassSelectorResolver,
public Resolution resolve(ClassSelector selector, Context context) {Class<?> testClass = selector.getJavaClass();//校验当前testClass是否是测试类if (isTestClassWithTests.test(testClass)) {// Nested tests are never filtered outif (classNameFilter.test(testClass.getName())) {//生成resolutionreturn toResolution(//生成ClassTestDescriptor,同时关联父子关系,当前parent为JupiterEngineDescriptorcontext.addToParent(parent -> Optional.of(newClassTestDescriptor(parent, testClass))));}}else if (isNestedTestClass.test(testClass)) {......}return unresolved();}private Resolution toResolution(Optional<? extends ClassBasedTestDescriptor> testDescriptor) {return testDescriptor.map(it -> {Class<?> testClass = it.getTestClass();//默认testClasses 为空List<Class<?>> testClasses = new ArrayList<>(it.getEnclosingTestClasses());testClasses.add(testClass);// @formatter:offreturn Resolution.match(//构造一个包含子类selector的match对象Match.exact(it, () -> {//查找测试类中测试方法,生成子selector,即MethodSelectorStream<DiscoverySelector> methods = findMethods(testClass, isTestOrTestFactoryOrTestTemplateMethod).stream().map(method -> selectMethod(testClasses, method));//查找内嵌测试class,忽略Stream<NestedClassSelector> nestedClasses = findNestedClasses(testClass, isNestedTestClass).stream().map(nestedClass -> new NestedClassSelector(testClasses, nestedClass));return Stream.concat(methods, nestedClasses).collect(toCollection((Supplier<Set<DiscoverySelector>>) LinkedHashSet::new));}));// @formatter:on}).orElse(unresolved());}public static Match exact(TestDescriptor testDescriptor,Supplier<Set<? extends DiscoverySelector>> childSelectorsSupplier) {return new Match(testDescriptor, childSelectorsSupplier, Type.EXACT);}
现在再循环解析selector,就存在MethodSelector了,对应解析器为MethodSelectorResolver,
private Resolution resolve(Context context, List<Class<?>> enclosingClasses, Class<?> testClass, Method method) {// @formatter:off//MethodType是个枚举,遍历MethodType转为stream,依次调用methodType的resolve方法Set<Match> matches = Arrays.stream(MethodType.values()).map(methodType -> methodType.resolve(enclosingClasses, testClass, method, context, configuration)).filter(Optional::isPresent).map(Optional::get)//expansionCallback 获取Filterable类型的 TestDescriptor,忽略.map(testDescriptor -> Match.exact(testDescriptor, expansionCallback(testDescriptor))).collect(toSet());// @formatter:onif (matches.size() > 1) {......}//通过 Resolution matches(Set<Match> matches) 方法生成 resolutionreturn matches.isEmpty() ? unresolved() : matches(matches);}private enum MethodType {//最常用的test类型TEST(new IsTestMethod(), TestMethodTestDescriptor.SEGMENT_TYPE) {@Overrideprotected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class<?> testClass, Method method,JupiterConfiguration configuration) {return new TestMethodTestDescriptor(uniqueId, testClass, method, configuration);}},TEST_FACTORY(new IsTestFactoryMethod(), TestFactoryTestDescriptor.SEGMENT_TYPE,TestFactoryTestDescriptor.DYNAMIC_CONTAINER_SEGMENT_TYPE,TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE) {@Overrideprotected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class<?> testClass, Method method,JupiterConfiguration configuration) {return new TestFactoryTestDescriptor(uniqueId, testClass, method, configuration);}},......private final Predicate<Method> methodPredicate;private final String segmentType;private final Set<String> dynamicDescendantSegmentTypes;// 构造方法MethodType(Predicate<Method> methodPredicate, String segmentType, String... dynamicDescendantSegmentTypes) {this.methodPredicate = methodPredicate;this.segmentType = segmentType;this.dynamicDescendantSegmentTypes = new LinkedHashSet<>(Arrays.asList(dynamicDescendantSegmentTypes));}//resolve方法private Optional<TestDescriptor> resolve(List<Class<?>> enclosingClasses, Class<?> testClass, Method method,Context context, JupiterConfiguration configuration) {// 调用Predicate方法校验,Test枚举对应new IsTestMethod()if (!methodPredicate.test(method)) {return Optional.empty();}// 关联parent ClassTestDescriptor和当前 MethodType中各枚举值对应的 createTestDescriptor创建的 TestDescriptor//当前为 子TestDescriptor 为 TestMethodTestDescriptorreturn context.addToParent(() -> selectClass(enclosingClasses, testClass), //parent -> Optional.of(createTestDescriptor(createUniqueId(method, parent), testClass, method, configuration)));}......}
至此,从通过idea传入request对象,到循环解析其中的父selector和子selector,通过addToParent方法构建父子TestDescriptor关联关系,完成了测试类到测试方法等解析工作,最后返回了根节点TestDescriptor即JupiterEngineDescriptor对象,和上篇描述的discoverRoot方法中处理流程一致
......//发现并生成和关联各层级TestDescriptor对象,最后返回根节点engine testDescriptorOptional<TestDescriptor> engineRoot = discoverEngineRoot(testEngine, discoveryRequest);......
解析测试文件生成TestDescriptor后,后面流程就可以开始执行对应测试用例了
To be continued...




