您的解决方案没有杀死生成的 JVM 背后的原因可能是因为您正在调用cmd.exe
,并且从内部调用您可能正在生成 JVM。因此,当您调用时,destroyProcess()
我相信它cmd.exe
会被杀死,但不会java.exe
。
您应该尝试将命令行更改为如下所示:
java -cp D:\MyProject\Utilities*;D:\MyProject\bin org.testng.TestNG D:\MyProject\testng.xml
这是一个解决方案,它不使用 Apache commons executor 来执行此操作,而是在单个 JVM 中管理所有内容,还提供了一种从 TestNG 检索输出和错误输出的方法。
该解决方案利用了 TestNG API。
使用 TestNG 运行测试的主测试运行器在不同的线程中如下所示
import org.testng.TestNG;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SimpleTestRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.err.println("***Main Thread running in Thread [" + Thread.currentThread().getId() + "]***");
ExecutorService service = Executors.newCachedThreadPool();
WorkerThread thread = new WorkerThread(SampleTestClass.class);
List<Future<ExecutionResults>> allResults = service.invokeAll(Collections.singletonList(thread));
service.shutdown();
ExecutionResults result = allResults.get(0).get();
System.err.println("******Printing the TestNG output******");
System.err.println(result);
System.err.println("**************************************");
}
public static class WorkerThread implements Callable<ExecutionResults> {
private Class<?>[] classes;
WorkerThread(Class<?>... classes) {
this.classes = classes;
}
@Override
public ExecutionResults call() throws Exception {
System.err.println("***Worker Thread running in Thread [" + Thread.currentThread().getId() + "]***");
TestNG testNG = new TestNG();
ExecutionResults results;
testNG.setVerbose(2);
ConsoleCapturer capturer = new ConsoleCapturer();
testNG.setTestClasses(classes);
try {
capturer.start();
testNG.run();
} finally {
ConsoleCapturer.CapturedData data = capturer.stop();
results = new ExecutionResults(data, testNG.getStatus());
}
return results;
}
}
public static class ExecutionResults {
private ConsoleCapturer.CapturedData data;
private int status;
public ExecutionResults(ConsoleCapturer.CapturedData data, int status) {
this.data = data;
this.status = status;
}
public ConsoleCapturer.CapturedData getData() {
return data;
}
public int getStatus() {
return status;
}
@Override
public String toString() {
return "ExecutionResults{" +
"data=" + getData() +
", status=" + getStatus() +
'}';
}
}
}
将所有输出和错误内容重定向到线程的实用程序类,以便可以将它们重定向到任何地方,如下所示:
这个类主要是从解决方案Redirect console output to string in java 中借用的代码,并进行了一些即兴创作。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
/**
* This class is an improvisation of the solution provided in https://stackoverflow.com/a/30665299/679824
*/
public class ConsoleCapturer {
private ByteArrayOutputStream baosOutput, baosError;
private PrintStream previousOut, previousError;
private boolean capturing;
public void start() {
if (capturing) {
return;
}
capturing = true;
previousOut = System.out;
previousError = System.err;
baosOutput = new ByteArrayOutputStream();
baosError = new ByteArrayOutputStream();
System.setOut(new PrintStream(new OutputStreamCombiner(previousOut, baosOutput)));
System.setErr(new PrintStream(new OutputStreamCombiner(previousError, baosError)));
}
public CapturedData stop() {
if (!capturing) {
return new CapturedData();
}
System.setOut(previousOut);
System.setErr(previousError);
String output = baosOutput.toString();
String error = baosError.toString();
try {
baosOutput.close();
baosError.close();
} catch (IOException e) {
e.printStackTrace();
}
baosOutput = null;
previousOut = null;
capturing = false;
return new CapturedData(output, error);
}
private static class OutputStreamCombiner extends OutputStream {
private OutputStream[] outputStreams;
OutputStreamCombiner(OutputStream... outputStreams) {
this.outputStreams = outputStreams;
}
public void write(int b) throws IOException {
for (OutputStream os : outputStreams) {
os.write(b);
}
}
public void flush() throws IOException {
for (OutputStream os : outputStreams) {
os.flush();
}
}
public void close() throws IOException {
for (OutputStream os : outputStreams) {
os.close();
}
}
}
public static class CapturedData {
private String output;
private String error;
CapturedData() {
this("", "");
}
public CapturedData(String output, String error) {
this.output = output;
this.error = error;
}
public String getError() {
return error;
}
public String getOutput() {
return output;
}
@Override
public String toString() {
return "CapturedData{" +
"output='" + getOutput() + '\'' +
", error='" + getError() + '\'' +
'}';
}
}
}
使用的测试类如下所示
import org.testng.annotations.Test;
public class SampleTestClass {
@Test
public void testMethod() {
System.err.println("This goes into the error console");
System.out.println("This goes into the console");
}
}
输出如下所示
***Main Thread running in Thread [1]***
***Worker Thread running in Thread [11]***
This goes into the console
This goes into the error console
PASSED: testMethod
===============================================
Command line test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
******Printing the TestNG output******
ExecutionResults{data=CapturedData{output='This goes into the console
PASSED: testMethod
===============================================
Command line test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
', error='This goes into the error console
'}, status=0}
**************************************
Process finished with exit code 0