如何使用 junit5 平台启动器 api 从队列中发现测试?
How do I use the junit5 platform launcher api to discover tests from a queue?
我希望将测试分发到 junit5 独立控制台的多个实例,每个实例都从队列中读取。 runner 的每个实例都会在类路径上使用相同的 test.jar,所以我不会在这里分发实际测试的字节代码,只是测试/过滤器模式字符串的名称。
根据 junit 5 advanced topics doc,我认为扩展 junit 5 的适当位置是使用平台启动器 api。我将这段代码主要与指南中的示例代码拼凑在一起。我认为这是我需要写的,但我担心我过度简化了这里涉及的工作:
// keep pulling test classes off the queue until its empty
while(myTestQueue.isNotEmpty()) {
String classFromQueue = myTestQueue.next(); //returns "org.myorg.foo.fooTests"
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(classFromQueue)).build();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
try (LauncherSession session = LauncherFactory.openSession()) {
Launcher launcher = session.getLauncher();
launcher.registerTestExecutionListeners(listener);
TestPlan testPlan = launcher.discover(request);
launcher.execute(testPlan);
}
TestExecutionSummary summary = listener.getSummary();
addSummary(summary);
}
问题:
- 在while循环中重复发现和执行是否会违反正常的测试生命周期?我有点不清楚发现是否是一次性的事情,应该在所有处决之前发生。
- 如果我假设可以重复发现然后执行,我发现 HierarchicalTestEngine 可能是从队列中读取的更好的地方,因为它似乎用于实现并行执行。这更适合我的用例吗?除了我可能不需要处理累积的测试摘要外,该实现是否与我上面的实现基本相同?
我不想采用的方法:
我不打算使用旨在在同一 jvm 中并行化测试执行的 junit 5 的新功能。我也不打算提前划分测试或 类;使用预先确定的测试子集启动每个控制台运行器实例。
简答
问题中发布的代码(松散地)说明了一种有效的方法。无需创建自定义引擎。利用平台启动器 api 重复发现和执行测试确实有效。我认为值得强调的是您不必扩展 junit5 这不是通过您需要注册的扩展来执行的,就像我最初假设的那样。您只是简单地利用平台启动器 api 来发现和执行测试。
长答案
这里是一些示例代码,其中包含存在于 class 路径上的简单测试队列 class 名称。当队列不为空时,testNode class 的实例将发现并执行三个测试中的每一个 classes 并编写 LegacyXmlReport。
测试节点代码:
package org.sample.node;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.LauncherSession;
import org.junit.platform.launcher.TestPlan;
import org.junit.platform.launcher.core.LauncherConfig;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.Queue;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
public class TestNode {
public void run() throws FileNotFoundException {
// keep pulling test classes off the queue until its empty
Queue<String> queue = getQueue();
while(!queue.isEmpty()) {
String testClass = queue.poll();
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(testClass)).build();
LauncherConfig launcherConfig = LauncherConfig.builder()
.addTestExecutionListeners(new LegacyXmlReportGeneratingListener(Paths.get("target"), new PrintWriter(new FileOutputStream("log.txt"))))
.build();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
try (LauncherSession session = LauncherFactory.openSession(launcherConfig)) {
Launcher launcher = session.getLauncher();
launcher.registerTestExecutionListeners(listener);
TestPlan testPlan = launcher.discover(request);
launcher.execute(testPlan);
}
}
}
private Queue<String> getQueue(){
Queue<String> queue = new LinkedList<>();
queue.add("org.sample.tests.Class1");
queue.add("org.sample.tests.Class2");
queue.add("org.sample.tests.Class3");
return queue;
}
public static void main(String[] args) throws FileNotFoundException {
TestNode node = new TestNode();
node.run();
}
}
TestNode 执行的测试
我只展示三个测试 class 中的一个,因为它们都是相同的东西,只是 class 名称不同。
它们位于 src/main/java 而不是 src/test/java。这是 maven 中用于将测试打包到 fat jar 中的一种公认的奇怪但常见的模式。
package org.sample.tests;
import org.junit.jupiter.api.Test;
public class Class1 {
@Test
void test1() {
System.out.println("Class1 Test 1");
}
@Test
void test2() {
System.out.println("Class1 Test 2");
}
@Test
void test3() {
System.out.println("Class1 Test 3");
}
}
我希望将测试分发到 junit5 独立控制台的多个实例,每个实例都从队列中读取。 runner 的每个实例都会在类路径上使用相同的 test.jar,所以我不会在这里分发实际测试的字节代码,只是测试/过滤器模式字符串的名称。
根据 junit 5 advanced topics doc,我认为扩展 junit 5 的适当位置是使用平台启动器 api。我将这段代码主要与指南中的示例代码拼凑在一起。我认为这是我需要写的,但我担心我过度简化了这里涉及的工作:
// keep pulling test classes off the queue until its empty
while(myTestQueue.isNotEmpty()) {
String classFromQueue = myTestQueue.next(); //returns "org.myorg.foo.fooTests"
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(classFromQueue)).build();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
try (LauncherSession session = LauncherFactory.openSession()) {
Launcher launcher = session.getLauncher();
launcher.registerTestExecutionListeners(listener);
TestPlan testPlan = launcher.discover(request);
launcher.execute(testPlan);
}
TestExecutionSummary summary = listener.getSummary();
addSummary(summary);
}
问题:
- 在while循环中重复发现和执行是否会违反正常的测试生命周期?我有点不清楚发现是否是一次性的事情,应该在所有处决之前发生。
- 如果我假设可以重复发现然后执行,我发现 HierarchicalTestEngine 可能是从队列中读取的更好的地方,因为它似乎用于实现并行执行。这更适合我的用例吗?除了我可能不需要处理累积的测试摘要外,该实现是否与我上面的实现基本相同?
我不想采用的方法: 我不打算使用旨在在同一 jvm 中并行化测试执行的 junit 5 的新功能。我也不打算提前划分测试或 类;使用预先确定的测试子集启动每个控制台运行器实例。
简答
问题中发布的代码(松散地)说明了一种有效的方法。无需创建自定义引擎。利用平台启动器 api 重复发现和执行测试确实有效。我认为值得强调的是您不必扩展 junit5 这不是通过您需要注册的扩展来执行的,就像我最初假设的那样。您只是简单地利用平台启动器 api 来发现和执行测试。
长答案
这里是一些示例代码,其中包含存在于 class 路径上的简单测试队列 class 名称。当队列不为空时,testNode class 的实例将发现并执行三个测试中的每一个 classes 并编写 LegacyXmlReport。
测试节点代码:
package org.sample.node;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.LauncherSession;
import org.junit.platform.launcher.TestPlan;
import org.junit.platform.launcher.core.LauncherConfig;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.Queue;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
public class TestNode {
public void run() throws FileNotFoundException {
// keep pulling test classes off the queue until its empty
Queue<String> queue = getQueue();
while(!queue.isEmpty()) {
String testClass = queue.poll();
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(testClass)).build();
LauncherConfig launcherConfig = LauncherConfig.builder()
.addTestExecutionListeners(new LegacyXmlReportGeneratingListener(Paths.get("target"), new PrintWriter(new FileOutputStream("log.txt"))))
.build();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
try (LauncherSession session = LauncherFactory.openSession(launcherConfig)) {
Launcher launcher = session.getLauncher();
launcher.registerTestExecutionListeners(listener);
TestPlan testPlan = launcher.discover(request);
launcher.execute(testPlan);
}
}
}
private Queue<String> getQueue(){
Queue<String> queue = new LinkedList<>();
queue.add("org.sample.tests.Class1");
queue.add("org.sample.tests.Class2");
queue.add("org.sample.tests.Class3");
return queue;
}
public static void main(String[] args) throws FileNotFoundException {
TestNode node = new TestNode();
node.run();
}
}
TestNode 执行的测试
我只展示三个测试 class 中的一个,因为它们都是相同的东西,只是 class 名称不同。 它们位于 src/main/java 而不是 src/test/java。这是 maven 中用于将测试打包到 fat jar 中的一种公认的奇怪但常见的模式。
package org.sample.tests;
import org.junit.jupiter.api.Test;
public class Class1 {
@Test
void test1() {
System.out.println("Class1 Test 1");
}
@Test
void test2() {
System.out.println("Class1 Test 2");
}
@Test
void test3() {
System.out.println("Class1 Test 3");
}
}