- 参考链接
- 源码分析
- 自上而下的梳理
- Node , TestDescriptor, TestEngine, TestTask , ExecutionRequest 与重要的实现类
- Node 接口
- TestDescriptor 接口
- TestEngine 接口
- HierarchicalTestEngine
- HierarchicalTestExecutorService 是一个接口 主要三个方法
- SameThreadHierarchicalTestExecutorService
- TestTask
- NodeTestTask 实现了 TestTask
- ExecutionRequest
- AbstractTestDescriptor 实现 TestDescriptor
- JupiterTestDescriptor 继承AbstractTestDescriptor也实现了Node接口
- ClassBasedTestDescriptor 继承自JupiterTestDescriptor
- JupiterEngineExecutionContext
- Node实现类
- TestDescirptor 实现类
- TestEngine的实现类
- Node , TestDescriptor, TestEngine, TestTask , ExecutionRequest 与重要的实现类
参考链接
- https://blog.csdn.net/qq_27009225/article/details/108448937
- https://junit.org/junit5/docs/current/user-guide/
- http://maven.apache.org/surefire/maven-surefire-report-plugin/usage.html
- https://blog.csdn.net/u012260238/article/details/89575617
源码分析
概览

- JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
从运行分析源码
打印调用链
index: 0 ClassName: java.lang.Thread Method Name : getStackTraceindex: 1 ClassName: com.example.project.FirstTest Method Name : myFirstTestindex: 2 ClassName: sun.reflect.NativeMethodAccessorImpl Method Name : invoke0index: 3 ClassName: sun.reflect.NativeMethodAccessorImpl Method Name : invokeindex: 4 ClassName: sun.reflect.DelegatingMethodAccessorImpl Method Name : invokeindex: 5 ClassName: java.lang.reflect.Method Method Name : invokeindex: 6 ClassName: org.junit.platform.commons.util.ReflectionUtils Method Name : invokeMethodindex: 7 ClassName: org.junit.jupiter.engine.execution.MethodInvocation Method Name : proceedindex: 8 ClassName: org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation Method Name : proceedindex: 9 ClassName: org.junit.jupiter.engine.extension.TimeoutExtension Method Name : interceptindex: 10 ClassName: org.junit.jupiter.engine.extension.TimeoutExtension Method Name : interceptTestableMethodindex: 11 ClassName: org.junit.jupiter.engine.extension.TimeoutExtension Method Name : interceptTestMethodindex: 12 ClassName: org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall Method Name : lambda$ofVoidMethod$0index: 13 ClassName: org.junit.jupiter.engine.execution.ExecutableInvoker Method Name : lambda$invoke$0index: 14 ClassName: org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation Method Name : proceedindex: 15 ClassName: org.junit.jupiter.engine.execution.InvocationInterceptorChain Method Name : proceedindex: 16 ClassName: org.junit.jupiter.engine.execution.InvocationInterceptorChain Method Name : chainAndInvokeindex: 17 ClassName: org.junit.jupiter.engine.execution.InvocationInterceptorChain Method Name : invokeindex: 18 ClassName: org.junit.jupiter.engine.execution.ExecutableInvoker Method Name : invokeindex: 19 ClassName: org.junit.jupiter.engine.execution.ExecutableInvoker Method Name : invokeindex: 20 ClassName: org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor Method Name : lambda$invokeTestMethod$7index: 21 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 22 ClassName: org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor Method Name : invokeTestMethodindex: 23 ClassName: org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor Method Name : executeindex: 24 ClassName: org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor Method Name : executeindex: 25 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$6index: 26 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 27 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$8index: 28 ClassName: org.junit.platform.engine.support.hierarchical.Node Method Name : aroundindex: 29 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$9index: 30 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 31 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeRecursivelyindex: 32 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeindex: 33 ClassName: java.util.ArrayList Method Name : forEachindex: 34 ClassName: org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService Method Name : invokeAllindex: 35 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$6index: 36 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 37 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$8index: 38 ClassName: org.junit.platform.engine.support.hierarchical.Node Method Name : aroundindex: 39 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$9index: 40 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 41 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeRecursivelyindex: 42 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeindex: 43 ClassName: java.util.ArrayList Method Name : forEachindex: 44 ClassName: org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService Method Name : invokeAllindex: 45 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$6index: 46 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 47 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$8index: 48 ClassName: org.junit.platform.engine.support.hierarchical.Node Method Name : aroundindex: 49 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : lambda$executeRecursively$9index: 50 ClassName: org.junit.platform.engine.support.hierarchical.ThrowableCollector Method Name : executeindex: 51 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeRecursivelyindex: 52 ClassName: org.junit.platform.engine.support.hierarchical.NodeTestTask Method Name : executeindex: 53 ClassName: org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService Method Name : submitindex: 54 ClassName: org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor Method Name : executeindex: 55 ClassName: org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine Method Name : executeindex: 56 ClassName: org.junit.platform.launcher.core.EngineExecutionOrchestrator Method Name : executeindex: 57 ClassName: org.junit.platform.launcher.core.EngineExecutionOrchestrator Method Name : executeindex: 58 ClassName: org.junit.platform.launcher.core.EngineExecutionOrchestrator Method Name : lambda$execute$0index: 59 ClassName: org.junit.platform.launcher.core.EngineExecutionOrchestrator Method Name : withInterceptedStreamsindex: 60 ClassName: org.junit.platform.launcher.core.EngineExecutionOrchestrator Method Name : executeindex: 61 ClassName: org.junit.platform.launcher.core.DefaultLauncher Method Name : executeindex: 62 ClassName: org.junit.platform.launcher.core.DefaultLauncher Method Name : executeindex: 63 ClassName: org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher Method Name : executeindex: 64 ClassName: org.junit.platform.launcher.core.SessionPerRequestLauncher Method Name : executeindex: 65 ClassName: org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor Method Name : processAllTestClassesindex: 66 ClassName: org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor Method Name : access$000index: 67 ClassName: org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor Method Name : stopindex: 68 ClassName: org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor Method Name : stopindex: 69 ClassName: sun.reflect.NativeMethodAccessorImpl Method Name : invoke0index: 70 ClassName: sun.reflect.NativeMethodAccessorImpl Method Name : invokeindex: 71 ClassName: sun.reflect.DelegatingMethodAccessorImpl Method Name : invokeindex: 72 ClassName: java.lang.reflect.Method Method Name : invokeindex: 73 ClassName: org.gradle.internal.dispatch.ReflectionDispatch Method Name : dispatchindex: 74 ClassName: org.gradle.internal.dispatch.ReflectionDispatch Method Name : dispatchindex: 75 ClassName: org.gradle.internal.dispatch.ContextClassLoaderDispatch Method Name : dispatchindex: 76 ClassName: org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler Method Name : invokeindex: 77 ClassName: com.sun.proxy.$Proxy2 Method Name : stopindex: 78 ClassName: org.gradle.api.internal.tasks.testing.worker.TestWorker$3 Method Name : runindex: 79 ClassName: org.gradle.api.internal.tasks.testing.worker.TestWorker Method Name : executeAndMaintainThreadNameindex: 80 ClassName: org.gradle.api.internal.tasks.testing.worker.TestWorker Method Name : executeindex: 81 ClassName: org.gradle.api.internal.tasks.testing.worker.TestWorker Method Name : executeindex: 82 ClassName: org.gradle.process.internal.worker.child.ActionExecutionWorker Method Name : executeindex: 83 ClassName: org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker Method Name : callindex: 84 ClassName: org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker Method Name : callindex: 85 ClassName: worker.org.gradle.process.internal.worker.GradleWorkerMain Method Name : runindex: 86 ClassName: worker.org.gradle.process.internal.worker.GradleWorkerMain Method Name : main
SessionPerRequestLauncher
public void execute(LauncherDiscoveryRequest launcherDiscoveryRequest, TestExecutionListener... listeners) {
try (LauncherSession session = createSession()) {
session.getLauncher().execute(launcherDiscoveryRequest, listeners);
}
}
- LauncherDiscoveryRequest 接口
- DefaultDiscoveryRequest
- TestExecutionListener 空的
DefaultLauncherSession
- getLauncher
DefaultLauncher
```java public void execute(LauncherDiscoveryRequest discoveryRequest, TestExecutionListener… listeners) {
}Preconditions.notNull(discoveryRequest, "LauncherDiscoveryRequest must not be null"); Preconditions.notNull(listeners, "TestExecutionListener array must not be null"); Preconditions.containsNoNullElements(listeners, "individual listeners must not be null"); execute(InternalTestPlan.from(discover(discoveryRequest, EXECUTION)), listeners);
private void execute(InternalTestPlan internalTestPlan, TestExecutionListener[] listeners) { executionOrchestrator.execute(internalTestPlan, listeners); }
<a name="TBbR8"></a>
#### EngineExecutionOrchestrator
```java
void execute(InternalTestPlan internalTestPlan, TestExecutionListener... listeners) {
internalTestPlan.markStarted();
LauncherDiscoveryResult discoveryResult = internalTestPlan.getDiscoveryResult();
ConfigurationParameters configurationParameters = discoveryResult.getConfigurationParameters();
ListenerRegistry<TestExecutionListener> listenerRegistry = buildListenerRegistryForExecution(listeners);
withInterceptedStreams(configurationParameters, listenerRegistry, testExecutionListener -> {
testExecutionListener.testPlanExecutionStarted(internalTestPlan);
execute(discoveryResult, new ExecutionListenerAdapter(internalTestPlan, testExecutionListener));
testExecutionListener.testPlanExecutionFinished(internalTestPlan);
});
}
....
public void execute(LauncherDiscoveryResult discoveryResult, EngineExecutionListener listener) {
for (TestEngine testEngine : discoveryResult.getTestEngines()) {
TestDescriptor engineDescriptor = discoveryResult.getEngineTestDescriptor(testEngine);
if (engineDescriptor instanceof EngineDiscoveryErrorDescriptor) {
listener.executionStarted(engineDescriptor);
listener.executionFinished(engineDescriptor,
TestExecutionResult.failed(((EngineDiscoveryErrorDescriptor) engineDescriptor).getCause()));
}
else {
execute(engineDescriptor, listener, discoveryResult.getConfigurationParameters(), testEngine);
}
}
}
.....
private void execute(TestDescriptor engineDescriptor, EngineExecutionListener listener,
ConfigurationParameters configurationParameters, TestEngine testEngine) {
OutcomeDelayingEngineExecutionListener delayingListener = new OutcomeDelayingEngineExecutionListener(listener,
engineDescriptor);
try {
testEngine.execute(new ExecutionRequest(engineDescriptor, delayingListener, configurationParameters));
delayingListener.reportEngineOutcome();
}
catch (Throwable throwable) {
UnrecoverableExceptions.rethrowIfUnrecoverable(throwable);
delayingListener.reportEngineFailure(new JUnitException(
String.format("TestEngine with ID '%s' failed to execute tests", testEngine.getId()), throwable));
}
}
HierarchicalTestEngine
HierarchicalTestExecutor
- 执行请求 ExecutionReuqest
- 上下文 rootContext
- 执行服务, executorService
- 异常收集器的工厂
HierarchicalTestExecutorService //是一个接口
- 这里看他的实现类 SameThreadHierarchicalTestExecutorService
TestTask 相关有TestTaskContext 与 TestDescriptor 是个接口
NodeTeskTask
- execute主流程
executeRecursively
private void executeRecursively() { taskContext.getListener().executionStarted(testDescriptor); started = true; throwableCollector.execute(() -> { node.around(context, ctx -> { context = ctx; throwableCollector.execute(() -> { // @formatter:off List<NodeTestTask<C>> children = testDescriptor.getChildren().stream() .map(descriptor -> new NodeTestTask<C>(taskContext, descriptor)) .collect(toCollection(ArrayList::new)); // @formatter:on context = node.before(context); final DynamicTestExecutor dynamicTestExecutor = new DefaultDynamicTestExecutor(); context = node.execute(context, dynamicTestExecutor); if (!children.isEmpty()) { children.forEach(child -> child.setParentContext(context)); taskContext.getExecutorService().invokeAll(children); } throwableCollector.execute(dynamicTestExecutor::awaitFinished); }); throwableCollector.execute(() -> node.after(context)); }); }); }Node 接口


- TestMethodTestDescriptor 实现了Node接口
- invokeTestMethod
- ExecutableInvoker
- InvocationInterceptorChain
- MethodInvocation
自上而下的梳理
Node , TestDescriptor, TestEngine, TestTask , ExecutionRequest 与重要的实现类
Node 接口
是有关本节点的运行控制逻辑,如是否skip,运行 before和after 的代码等
TestDescriptor 接口
有Test 和Container两种类型 或两中都是,有很多树状结构数据维护的方法,
TestEngine 接口
主要是下面两个重要方法
- TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
void execute(ExecutionRequest request);
HierarchicalTestEngine
实现TestEngine 接口
- 主要就是实现execute 方法,
- 根据传入的ExecutionRequest 类型参数 创建了HierarchicalTestExecutorService的实现类SameThreadHierarchicalTestExecutorService 实例来执行
- new 了一个 HierarchicalTestExecutor 实例,把所有相关参数包括 HierarchicalTestExecutorService实例都传了进去
- HierarchicalTestExecutor 实例里面又调了HierarchicalTestExecutorService的 submit 来执行,入参是一个TeskTask实例,
HierarchicalTestExecutorService 是一个接口 主要三个方法
- Future
submit(TestTask testTask); - void invokeAll(List<? extends TestTask> testTasks);
- void close();
- 实现类
ForkJoinPoolHierarchicalTestExecutorService, SameThreadHierarchicalTestExecutorService
SameThreadHierarchicalTestExecutorService
- 实现 submit 和 invokeAll方法主要是调用 TestTask的execute 实现
TestTask
- HierarchicalTestExecutorService的内部接口
- 定义了getExecutionMode getResourceLock execute 方法
NodeTestTask 实现了 TestTask
- 实现了execute方法
主要逻辑在 executeRecursively 这个方法内
ExecutionRequest
三个属性
private final TestDescriptor rootTestDescriptor; private final EngineExecutionListener engineExecutionListener; private final ConfigurationParameters configurationParameters;AbstractTestDescriptor 实现 TestDescriptor
- TestSource 类型的属性,TestSource是个接口
- TestDescriptor 类型的 parent 和children属性, 是一个树的结构
其它是displayName 与 uniqueId , UniqueID 这个类型的意义? //TODO
JupiterTestDescriptor 继承AbstractTestDescriptor也实现了Node接口
公有方法,
属性 ```java private final Class<?> testClass; protected final Set
tags; protected final Lifecycle lifecycle; private ExecutionMode defaultChildExecutionMode; private TestInstanceFactory testInstanceFactory; private List
beforeAllMethods; private List afterAllMethods;
- 主要是三个public方法实现,
- prepare
- 注册extensions // extension 这个后面再仔细分析下
- 主要是构建一个 JupiterEngineExecutionContext 实例
```java
return context.extend()
.withTestInstancesProvider(testInstancesProvider(context, extensionContext))
.withExtensionRegistry(registry)
.withExtensionContext(extensionContext)
.withThrowableCollector(throwableCollector)
.build();
- before
- after
JupiterEngineExecutionContext
一个内部类 保存的重要属性 //调试时看下这些东西是什么东西
private static final class State implements Cloneable { final EngineExecutionListener executionListener; final JupiterConfiguration configuration; TestInstancesProvider testInstancesProvider; MutableExtensionRegistry extensionRegistry; ExtensionContext extensionContext; ThrowableCollector throwableCollector; ....Node实现类
ClassBasedTestDescriptor, ClassTestDescriptor, JupiterEngineDescriptor, JupiterTestDescriptor, MethodBasedTestDescriptor, NestedClassTestDescriptor, TestFactoryTestDescriptor, TestMethodTestDescriptor, TestTemplateInvocationTestDescriptor, TestTemplateTestDescriptor
TestDescirptor 实现类
AbstractTestDescriptor, ClassBasedTestDescriptor, ClassTestDescriptor, EngineDescriptor, JupiterEngineDescriptor, JupiterTestDescriptor, MethodBasedTestDescriptor, NestedClassTestDescriptor, RunnerTestDescriptor, TestFactoryTestDescriptor, TestMethodTestDescriptor, TestTemplateInvocationTestDescriptor, TestTemplateTestDescriptor, VintageEngineDescriptor, VintageTestDescriptor
TestEngine的实现类
HierarchicalTestEngine, JupiterTestEngine, SuiteTestEngine, VintageTestEngine
[
