前面讲了测试用例相关的数据结构是怎么生成的,当框架解析了测试用例后,后面就是执行了。执行方法的入口在DefaultLauncher.execute()方法
@Overridepublic void execute(LauncherDiscoveryRequest discoveryRequest, TestExecutionListener... listeners) {......execute(InternalTestPlan.from(discoverRoot(discoveryRequest, "execution")), listeners);}@Overridepublic void execute(TestPlan testPlan, TestExecutionListener... listeners) {......execute((InternalTestPlan) testPlan, listeners);}private void execute(InternalTestPlan internalTestPlan, TestExecutionListener[] listeners) {Root root = internalTestPlan.getRoot();ConfigurationParameters configurationParameters = root.getConfigurationParameters();TestExecutionListenerRegistry listenerRegistry = buildListenerRegistryForExecution(listeners);//构造lambda表达式,遍历testEngine,分别执行其中的testDescriptorwithInterceptedStreams(configurationParameters, listenerRegistry, testExecutionListener -> {......ExecutionListenerAdapter engineExecutionListener = new ExecutionListenerAdapter(internalTestPlan,testExecutionListener);//循环遍历testEngine 中的estDescriptor ,依次执行for (TestEngine testEngine : root.getTestEngines()) {TestDescriptor testDescriptor = root.getTestDescriptorFor(testEngine);execute(testEngine,//构造ExecutionRequest对象new ExecutionRequest(testDescriptor, engineExecutionListener, configurationParameters));}......});}
实际依次调用执行了三个execute方法,最后execute执行的参数是构造的InternalTestPlan对象,使用InternalTestPlan.from()方法生成
static InternalTestPlan from(Root root) {//生成委托对象,传入前面解析完成的根节点TestDescriptor即JupiterEngineDescriptorTestPlan delegate = TestPlan.from(root.getEngineDescriptors());return new InternalTestPlan(root, delegate);}public static TestPlan from(Collection<TestDescriptor> engineDescriptors) {Preconditions.notNull(engineDescriptors, "Cannot create TestPlan from a null collection of TestDescriptors");TestPlan testPlan = new TestPlan(engineDescriptors.stream().anyMatch(TestDescriptor::containsTests));//添加到testPlan中的allIdentifiers map中Visitor visitor = descriptor -> testPlan.add(TestIdentifier.from(descriptor));engineDescriptors.forEach(engineDescriptor -> engineDescriptor.accept(visitor));return testPlan;}
在withInterceptedStreams方法中,主要就是执行lambda表达式,所以重点还是execute(InternalTestPlan internalTestPlan, TestExecutionListener[] listeners)方法中的lambda表达式,如上述中循环遍历testEngine根节点,调用第四个execute方法 execute(TestEngine testEngine, ExecutionRequest executionRequest)执行,在其中调用testEngine的execute方法执行,入参ExecutionRequest 是一个包装类,主要包含TestDescriptor对象和EngineExecutionListener监听器对象
private void withInterceptedStreams(ConfigurationParameters configurationParameters,TestExecutionListenerRegistry listenerRegistry, Consumer<TestExecutionListener> action) {//获取CompositeTestExecutionListener,实际是个组合类,listener的组合,//其中主要调用notifyEach 方法依次执行所有的listener对应的方法,如executionStarted,executionFinished等TestExecutionListener testExecutionListener = listenerRegistry.getCompositeTestExecutionListener();......try {//执行lambda表达式action.accept(testExecutionListener);}finally {......}}private void execute(TestEngine testEngine, ExecutionRequest executionRequest) {try {//调用engine的excute方法testEngine.execute(executionRequest);}catch (Throwable throwable) {handleThrowable(testEngine, "execute", throwable);}}
说到testEngine的execute方法,我们先看看JupiterTestEngine的继承结构,如下图所示:

由于JupiterTestEngine中没有实现execute方法,会直接调用父类HierarchicalTestEngine中的execute方法
@Overridepublic final void execute(ExecutionRequest request) {//创建执行器service,如果没有并非执行相关配置,默认直接返回单线程执行器service//这里返回默认执行器service - SameThreadHierarchicalTestExecutorServicetry (HierarchicalTestExecutorService executorService = createExecutorService(request)) {//创建<C extends EngineExecutionContext>,这里返回JupiterEngineExecutionContext对象C executionContext = createExecutionContext(request);//返回包含 TestAbortedException(依赖于opentest4j库) Predicate<? super Throwable> 的 OpenTest4JAwareThrowableCollectorThrowableCollector.Factory throwableCollectorFactory = createThrowableCollectorFactory(request);//调用HierarchicalTestExecutor的execute方法,并get取得结果new HierarchicalTestExecutor<>(request, executionContext, executorService,throwableCollectorFactory).execute().get();}catch (Exception exception) {throw new JUnitException("Error executing tests for engine " + getId(), exception);}}//HierarchicalTestExecutor 的execute方法Future<Void> execute() {TestDescriptor rootTestDescriptor = this.request.getRootTestDescriptor();EngineExecutionListener executionListener = this.request.getEngineExecutionListener();//walk方法解决资源竞争的问题,当前不涉及NodeExecutionAdvisor executionAdvisor = new NodeTreeWalker().walk(rootTestDescriptor);//通过listener,executionService,throwableCollectorFactory,executionAdvisor构造taskContextNodeTestTaskContext taskContext = new NodeTestTaskContext(executionListener, this.executorService,this.throwableCollectorFactory, executionAdvisor);//通过taskContext和 根testDescriptor构造NodeTestTask对象,这个对象是后面执行测试用例的关键NodeTestTask<C> rootTestTask = new NodeTestTask<>(taskContext, rootTestDescriptor);rootTestTask.setParentContext(this.rootContext);//提交给executorService执行NodeTestTaskreturn this.executorService.submit(rootTestTask);}
NodeTestTask 是执行测试用例的关键,下节将详细讲解其执行流程。
To be continued...
文章转载自测开技术笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




