我正在爲我的應用程序的「膠合」層編寫單元測試,並且難以爲允許用戶過早取消操作的異步方法創建確定性測試。在長時間運行的單元測試中協調取消
具體來說,在一些異步方法中,我們有代碼對取消調用做出反應,並確保對象在完成之前處於適當狀態。我想確保這些代碼路徑被測試覆蓋。
某些C#僞代碼在此方案中例示的典型異步方法如下:
public void FooAsync(CancellationToken token, Action<FooCompletedEventArgs> callback)
{
if (token.IsCancellationRequested) DoSomeCleanup0();
// Call the four helper methods, checking for cancellations in between each
Exception encounteredException;
try
{
MyDependency.DoExpensiveStuff1();
if (token.IsCancellationRequested) DoSomeCleanup1();
MyDependency.DoExpensiveStuff2();
if (token.IsCancellationRequested) DoSomeCleanup2();
MyDependency.DoExpensiveStuff3();
if (token.IsCancellationRequested) DoSomeCleanup3();
MyDependency.DoExpensiveStuff4();
if (token.IsCancellationRequested) DoSomeCleanup4();
}
catch (Exception e)
{
encounteredException = e;
}
if (!token.IsCancellationRequested)
{
var args = new FooCompletedEventArgs(a bunch of params);
callback(args);
}
}
,我已想出迄今涉及嘲笑底層MyDependency
操作由膠水層包裹的溶液,並迫使每個人在任意一段時間內入睡。然後我調用異步方法,並告訴我的單元測試在取消異步請求之前休眠數毫秒。
像這樣(使用犀牛製品作爲示例):
[TestMethod]
public void FooAsyncTest_CancelAfter2()
{
// arrange
var myDependency = MockRepository.GenerateStub<IMyDependency>();
// Set these stubs up to take a little bit of time each so we can orcestrate the cancels
myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff2()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff4()).WhenCalled(x => Thread.Sleep(100));
// act
var target = new FooClass(myDependency);
CancellationTokenSource cts = new CancellationTokenSource();
bool wasCancelled = false;
target.FooAsync(
cts.Token,
args =>
{
wasCancelled = args.IsCancelled;
// Some other code to manipulate FooCompletedEventArgs
});
// sleep long enough for two operations to complete, then cancel
Thread.Sleep(250);
cts.Cancel();
// Some code to ensure the async call completes goes here
//assert
Assert.IsTrue(wasCancelled);
// Other assertions to validate state of target go here
}
從在單元測試使用了Thread.Sleep讓我反胃的事實
除了,更大的問題是,有時這樣的測試失敗在我們的構建服務器上,如果它恰好處於顯着負載下。異步呼叫太過分了,取消來得太遲。
任何人都可以提供一個更可靠的單元測試取消邏輯的長期運行操作像這樣嗎?任何想法,將不勝感激。
這看起來非常有前途。我今天下午試一試,然後再報告。 – 2010-06-08 15:55:16
它工作得很漂亮。謝謝你的幫助! – 2010-06-08 19:45:35