我是靠谱客的博主 聪慧钻石,最近开发中收集的这篇文章主要介绍JUnit5的启动 - Launcher启动过程中涉及的类DiscoverySelectorFilterLauncherDiscoveryRequestTestEngineDefaultLauncher,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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指定测试类的查找和过滤规则

2. 通过 LauncherFactory.create() 来获取Launcher默认实现

3. 通过添加TestExecutionListener来进行测试结果的监听

4. 执行launcher.execute(req)方法启动测试

简单来说就是扫描注定的文件夹或找到指定类名的类,经过Filter过滤后交给TestEngine去执行

启动过程中涉及的类

DiscoverySelector

负责定义哪些资源可以被TestEngine用来寻找测试类,比如指定java类名或者指定目录路径

Filter

作为TestEngine的过滤器,过滤DiscoverySelector发现的资源

LauncherDiscoveryRequest

使用不同的Filter定义了Launcher和TestEngine以及测试类的过滤规则,使用DiscoverySelector发现测试类

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的执行




Launcher构造和启动流程图











最后

以上就是聪慧钻石为你收集整理的JUnit5的启动 - Launcher启动过程中涉及的类DiscoverySelectorFilterLauncherDiscoveryRequestTestEngineDefaultLauncher的全部内容,希望文章能够帮你解决JUnit5的启动 - Launcher启动过程中涉及的类DiscoverySelectorFilterLauncherDiscoveryRequestTestEngineDefaultLauncher所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部