[英]How to abort unit test from another thread?
我有基本上運行 2 個線程的單元測試示例代碼:主測試線程和我正在啟動的另一個線程,它應該在一段時間后測試執行失敗(這基本上是一個超時線程)
代碼如下:
[TestClass]
public class SomeTestClass
{
[TestInitialize]
public void BeforeTest()
{
var task = new Task(abortIfTestStilRunsAfterTimeout);
task.Start();
}
[TestMethod]
public void TestMethod()
{
Thread.Sleep(5000);
}
private void abortIfTestStilRunsAfterTimeout()
{
Assert.Fail("timeout passed!");
}
}
好吧,我原以為TestMethod()
測試應該失敗,但實際發生的是運行Assert.Fail
方法的任務線程出現異常,而另一個線程繼續運行並且測試通過。
我正在尋找一種使測試方法失敗的方法
您可以嘗試獲取對測試線程的引用並在其上調用Abort()
。 您可以將異常 state object 傳遞給Abort()
,您可以使用它來傳遞失敗消息:
[TestClass]
public class SomeTestClass
{
Thread testThread;
[TestInitialize]
public void BeforeTest()
{
testThread = Thread.CurrentThread;
var task = new Task(abortIfTestStilRunsAfterTimeout);
task.Start();
}
[TestMethod]
public void TestMethod()
{
try
{
Thread.Sleep(5000);
}
catch (ThreadAbortException e)
{
Assert.Fail((string)e.ExceptionState);
}
}
private void abortIfTestStilRunsAfterTimeout()
{
testThread.Abort("timeout passed!");
}
}
如果您不想修改大約 100 個測試,您可以使用像 PostSharp 這樣的工具來修改您的測試用例,方法是為您在每個測試用例周圍插入try {} catch {}
邏輯。 歸結起來就是編寫一個屬性並用它裝飾你的測試程序集(它稱為面向方面的編程,PostSharp 中的框架稱為老撾)。
這個想法很簡單 - 只需在任務/線程中運行主要測試邏輯,並將超時處理代碼放在測試方法/測試初始化中。 某種控制反轉:
// Test class level
ManualResetEvent mre = new ManualResetEvent(false);
[TestMethod]
public void TestMethod()
{
// start waiting task
Task task = Task.Factory.StartNew(() =>
{
// Test Body HERE!
// ...
// if test passed - set event explicitly
mre.Set();
});
// Timeout handling logic,
// !!! I believe you can put it once in the TestInitialize, just check
// whether Assert.Fail() fails the test when called from TestInitialize
mre.WaitOne(5000);
// Check whether ManualResetEvent was set explicitly or was timeouted
if (!mre.WaitOne(0))
{
task.Dispose();
Assert.Fail("Timeout");
}
}
PS:關於WaitOne(0)
技巧, MSDN :
如果 millisecondsTimeout 為零,則該方法不會阻塞。 它測試等待句柄的 state 並立即返回。
這篇文章有點舊,但最近我遇到了類似的問題。
我的解決方案是不同的:
使用 NUnit TimeoutAttribute
請在此處查看 NUnit 文檔:
NUnit 2.5: https://nunit.org/docs/2.5/timeout.html
NUnit 3.0: https://github.com/nunit/docs/wiki/Timeout-Attribute
利用TimeoutAttribute
和/或TestContext.CancellationTokenSource
的解決方案:
[TestClass]
public class SomeTestClass
{
private Task abortTask;
// Test runner will set this automatically.
public TestContext Context { get; set; }
[TestInitialize]
public void BeforeTest()
{
this.abortTask = Task.Run(
() =>
{
this.WaitForAbort();
this.Context.CancellationTokenSource.Cancel();
});
}
[TestMethod]
public Task TestMethod1()
{
// Cancellation triggered by manual abort logic.
this.TestWithCancellation(Context.CancellationTokenSource.Token);
}
[TestMethod]
[Timeout(5000)]
public Task TestMethod2()
{
// Cancellation triggered automatically by the runner after 5 sec.
this.TestWithCancellation(Context.CancellationTokenSource.Token);
}
private void WaitForAbort()
{
// Concurrently check for some abort condition...
}
private void TestWithCancellation(CancellationToken cancellationToken)
{
// Do your test, but pass/respect the token!
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.