如何停止 NUnit ITestRunner?
How to stop NUnit ITestRunner?
使用 nunit.engine 3.10.0,我无法异步停止 运行 ITestRunner
。 TestPackage
设置为在本地执行,即 InProcess 和当前 AppDomain 中。第二次测试后没有像预期的那样开始更多测试,但是 while 循环永远不会结束。
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
// prepare a listener that stops the test runner
// when the second test has been started
const bool StopAfterSecondTest = true;
int testStartedCount = 0;
var listener = new MyTestEventListener();
listener.TestStarted += (sender, eventArgs) =>
{
testStartedCount++;
if ( StopAfterSecondTest && testStartedCount == 2 )
{
testRunner.StopRun(force: true);
}
};
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
bool keepRunning;
int loopCount = 0;
do
{
bool completed = testRun.Wait(500);
bool running = testRunner.IsTestRunning;
keepRunning = !completed && running;
loopCount++;
} while ( keepRunning );
Console.WriteLine($"Loop count: {loopCount}");
XmlNode resultNode = testRun.Result;
Console.WriteLine(resultNode.InnerText);
Console.ReadKey();
}
private class MyTestEventListener : ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
TestStarted?.Invoke(this, new EventArgs());
}
}
}
如果我跳过等待并尝试获取测试结果,我会得到 InvalidOperationException
:'Cannot retrieve Result from an incomplete or cancelled TestRun.'
如何停止测试运行程序并获取停止前完成的测试结果?
您不能在测试中执行此操作。您的侦听器在测试本身的上下文中执行。出于这个原因,特别禁止听众试图改变测试的结果。此外,事件被缓冲,在这种情况下甚至可能直到测试 运行 完成后才被接收。
StopRun 旨在由主要 运行ner 本身调用,通常由某些用户输入触发。
您还应注意此问题:https://github.com/nunit/nunit/issues/3276 which prevents StopRun(true)
from working under any circumstances. It was fixed in PR https://github.com/nunit/nunit/pull/3281 但尚未出现在框架的任何版本中。您将不得不使用框架的最新开发版本或切换到 StopRun(false)
.
基于@Charlie 的,这是修改代码以停止所有线程的方法:
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
// each test case includes a 200 ms delay
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
var listener = new TestStartListener();
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
// wait until the first test case has been started
while ( listener.Count < 1 )
{
Thread.Sleep(50);
}
bool keepRunning = true;
while ( keepRunning )
{
int testStartedCount = listener.Count;
testRunner.StopRun(force: false);
Writer.WriteLine($"{GetTimeStamp()}, Stop requested after {testStartedCount} test cases.");
// wait for less time than a single test needs to complete
bool completed = testRun.Wait(100);
bool running = testRunner.IsTestRunning;
Writer.WriteLine($"{GetTimeStamp()} Completed: {completed}, running: {running}");
keepRunning = !completed && running;
}
listener.WriteReportsTo(Writer);
XmlNode resultNode = testRun.Result;
Writer.WriteLine("Test result:");
resultNode.WriteContentTo(ResultWriter);
Console.ReadKey();
}
private class TestStartListener : List<string>, ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
Add($"{GetTimeStamp()}, {report}");
TestStarted?.Invoke(this, new EventArgs());
}
}
public void WriteReportsTo(TextWriter writer)
{
Writer.WriteLine($"Listener was called {Count} times.");
foreach ( var report in this )
{
Writer.WriteLine(report);
}
}
}
两个测试程序集在运行程序的进程中执行,在单个域和两个线程上,每个测试程序集一个。总共执行并通过了两个测试方法;一个用于两个测试组件中的每一个。其他测试方法不会被执行也不会被报告。其他测试装置 (类) 不会被执行并被报告为 result="Failed" label="Cancelled"
.
注意testRunner.StopRun(force: false)
被重复调用。如果只调用一次,其他线程将运行完成。
使用 nunit.engine 3.10.0,我无法异步停止 运行 ITestRunner
。 TestPackage
设置为在本地执行,即 InProcess 和当前 AppDomain 中。第二次测试后没有像预期的那样开始更多测试,但是 while 循环永远不会结束。
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
// prepare a listener that stops the test runner
// when the second test has been started
const bool StopAfterSecondTest = true;
int testStartedCount = 0;
var listener = new MyTestEventListener();
listener.TestStarted += (sender, eventArgs) =>
{
testStartedCount++;
if ( StopAfterSecondTest && testStartedCount == 2 )
{
testRunner.StopRun(force: true);
}
};
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
bool keepRunning;
int loopCount = 0;
do
{
bool completed = testRun.Wait(500);
bool running = testRunner.IsTestRunning;
keepRunning = !completed && running;
loopCount++;
} while ( keepRunning );
Console.WriteLine($"Loop count: {loopCount}");
XmlNode resultNode = testRun.Result;
Console.WriteLine(resultNode.InnerText);
Console.ReadKey();
}
private class MyTestEventListener : ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
TestStarted?.Invoke(this, new EventArgs());
}
}
}
如果我跳过等待并尝试获取测试结果,我会得到 InvalidOperationException
:'Cannot retrieve Result from an incomplete or cancelled TestRun.'
如何停止测试运行程序并获取停止前完成的测试结果?
您不能在测试中执行此操作。您的侦听器在测试本身的上下文中执行。出于这个原因,特别禁止听众试图改变测试的结果。此外,事件被缓冲,在这种情况下甚至可能直到测试 运行 完成后才被接收。
StopRun 旨在由主要 运行ner 本身调用,通常由某些用户输入触发。
您还应注意此问题:https://github.com/nunit/nunit/issues/3276 which prevents StopRun(true)
from working under any circumstances. It was fixed in PR https://github.com/nunit/nunit/pull/3281 但尚未出现在框架的任何版本中。您将不得不使用框架的最新开发版本或切换到 StopRun(false)
.
基于@Charlie 的
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
// each test case includes a 200 ms delay
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
var listener = new TestStartListener();
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
// wait until the first test case has been started
while ( listener.Count < 1 )
{
Thread.Sleep(50);
}
bool keepRunning = true;
while ( keepRunning )
{
int testStartedCount = listener.Count;
testRunner.StopRun(force: false);
Writer.WriteLine($"{GetTimeStamp()}, Stop requested after {testStartedCount} test cases.");
// wait for less time than a single test needs to complete
bool completed = testRun.Wait(100);
bool running = testRunner.IsTestRunning;
Writer.WriteLine($"{GetTimeStamp()} Completed: {completed}, running: {running}");
keepRunning = !completed && running;
}
listener.WriteReportsTo(Writer);
XmlNode resultNode = testRun.Result;
Writer.WriteLine("Test result:");
resultNode.WriteContentTo(ResultWriter);
Console.ReadKey();
}
private class TestStartListener : List<string>, ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
Add($"{GetTimeStamp()}, {report}");
TestStarted?.Invoke(this, new EventArgs());
}
}
public void WriteReportsTo(TextWriter writer)
{
Writer.WriteLine($"Listener was called {Count} times.");
foreach ( var report in this )
{
Writer.WriteLine(report);
}
}
}
两个测试程序集在运行程序的进程中执行,在单个域和两个线程上,每个测试程序集一个。总共执行并通过了两个测试方法;一个用于两个测试组件中的每一个。其他测试方法不会被执行也不会被报告。其他测试装置 (类) 不会被执行并被报告为 result="Failed" label="Cancelled"
.
注意testRunner.StopRun(force: false)
被重复调用。如果只调用一次,其他线程将运行完成。