Launcher概述
Launcher是JUnit5的啓動類,也是對啓動進行擴展的主要入口,擴展通過實現自定義的TestEngine來自定義測試類的發現和執行邏輯以達到定製化測試的目的
Launcher啓動示例代碼
public static void main(String[] args) {
//設置搜索和過濾規則
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(
selectPackage("zj"),
selectClass(*MyTest.class)
)
.filters(
includeClassNamePatterns(".*Tests")
)
.build();
Launcher launcher = LauncherFactory.create();
// Register a listener of your choice
//通過監聽器來監聽獲取執行結果
TestExecutionListener listener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
}
啓動分爲如下幾步:
1. 構造LauncherDiscoveryRequest指定測試類的查找和過濾規則
簡單來說就是掃描註定的文件夾或找到指定類名的類,經過Filter過濾後交給TestEngine去執行2. 通過 LauncherFactory.create() 來獲取Launcher默認實現
3. 通過添加TestExecutionListener來進行測試結果的監聽
4. 執行launcher.execute(req)方法啓動測試
啓動過程中涉及的類
DiscoverySelector
負責定義哪些資源可以被TestEngine用來尋找測試類,比如指定java類名或者指定目錄路徑
Filter
LauncherDiscoveryRequest
TestEngine
作爲發現和執行符合LauncherDiscoveryRequest規則的測試的主要組件,對不同的編程模型可以實現自己的TestEngine,比如JupiterTestEngine
TestEngine在創建Launcher的時候通過JAVA SPI發現具體實現,JUnit5中有兩種實現 :JupiterTestEngine 和 VintageTestEngine
TestExecutionListener
定義了測試執行期間發生的事件類型,註冊到Launcher的實現類將會在事件發生時得到通知
DefaultLauncher
做爲Launcher的默認實現,持有TestEngine和TestExecutionListener集合,它們通過JAVA SPI發現,負責執行TestEngine來啓動測試
各步驟詳解
1. 構造LauncherDiscoveryRequest指定測試類的查找和過濾規則
public LauncherDiscoveryRequest build() {
LauncherConfigurationParameters launcherConfigurationParameters = new LauncherConfigurationParameters(
this.configurationParameters);
return new DefaultDiscoveryRequest(this.selectors, this.engineFilters, this.discoveryFilters,
this.postDiscoveryFilters, launcherConfigurationParameters);
}
2.利用LauncherFactory創建DefaultLauncher
public static Launcher create() throws PreconditionViolationException {
Launcher launcher = new DefaultLauncher(new ServiceLoaderTestEngineRegistry().loadTestEngines());
for (TestExecutionListener listener : new ServiceLoaderTestExecutionListenerRegistry().loadListeners()) {
launcher.registerTestExecutionListeners(listener);
}
return launcher;
}
這裏利用JAVA SPI來發現TestEngine和TestExecutionListener的實現集合,保存在Launcher中
3. 通過添加TestExecutionListener來進行測試結果的監聽
TestExecutionListener listener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(listener);
4. 執行launcher.execute(req)方法啓動測試
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(discoverRoot(discoveryRequest, "execution"), discoveryRequest.getConfigurationParameters(), listeners);
}
4.1 調用discoveryRoot()來執行TestEngine的過濾器,過濾的結果通過類Root返回,Root持有TestEngine的map集合 private Root discoverRoot(LauncherDiscoveryRequest discoveryRequest, String phase) {
Root root = new Root();
for (TestEngine testEngine : this.testEngines) {
// @formatter:off
boolean engineIsExcluded = discoveryRequest.getEngineFilters().stream()
.map(engineFilter -> engineFilter.apply(testEngine))
.anyMatch(FilterResult::excluded);
// @formatter:on
if (engineIsExcluded) {
logger.debug(() -> String.format(
"Test discovery for engine '%s' was skipped due to an EngineFilter in phase '%s'.",
testEngine.getId(), phase));
continue;
}
logger.debug(() -> String.format("Discovering tests during Launcher %s phase in engine '%s'.", phase,
testEngine.getId()));
Optional<TestDescriptor> engineRoot = discoverEngineRoot(testEngine, discoveryRequest);
engineRoot.ifPresent(rootDescriptor -> root.add(testEngine, rootDescriptor));
}
root.applyPostDiscoveryFilters(discoveryRequest);
root.prune();
return root;
}
4.2 繼續調用execute(Root ...)
private void execute(Root root, ConfigurationParameters configurationParameters,
TestExecutionListener... listeners) {
TestExecutionListenerRegistry listenerRegistry = buildListenerRegistryForExecution(listeners);
TestPlan testPlan = TestPlan.from(root.getEngineDescriptors());
TestExecutionListener testExecutionListener = listenerRegistry.getCompositeTestExecutionListener();
testExecutionListener.testPlanExecutionStarted(testPlan);
ExecutionListenerAdapter engineExecutionListener = new ExecutionListenerAdapter(testPlan,
testExecutionListener);
for (TestEngine testEngine : root.getTestEngines()) {
TestDescriptor testDescriptor = root.getTestDescriptorFor(testEngine);
execute(testEngine, new ExecutionRequest(testDescriptor, engineExecutionListener, configurationParameters));
}
testExecutionListener.testPlanExecutionFinished(testPlan);
}
主要邏輯就是構造監聽器、TestDescriptor和ExecutionRequest的構造以及TestEngine的執行