這是我如何做到這一點:
[Test]
public void ObservesTaskException()
{
bool wasUnobservedException = false;
TaskScheduler.UnobservedTaskException +=
(s, args) => wasUnobservedException = true;
CauseATaskToThrowInTheSystemUnderTest();
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(wasUnobservedException, Is.False);
}
到CauseATaskToThrowInTheSystemUnderTest()的調用是任何你需要做的佔位符。我建議將代碼包裝在這樣的函數中,因爲它有助於確保在GC運行時引發異常的Task對象無法訪問。如果任務對象可達,終結器將不會運行,並且此測試不會測試任何內容。
顯然,在垃圾收集發生之前確保任務已完成也很重要。你如何做到這一點(如果你可以的話)取決於你的特定代碼。也許你的程序流程確保了這種情況。如果不是這樣,如果你的測試可以訪問任務的對象,你可以做到以下幾點:
var continuation = GetTheTaskFromTheSystemUnderTest();
.ContinueWith(t => {});
CauseATaskToThrowInTheSystemUnderTest();
bool isTaskCompleted = continuation.Wait(SomeSuitableTimeout);
您應該添加isTaskCompleted把斷言。
超時時間是爲了防止將來代碼被破壞 - 您不希望測試掛起。該值應該非常小。如果您發現實際上需要等待很長時間才能完成任務,那麼您的測試套件對於頻繁使用可能會太慢。
有權訪問您創建的任務(包括您在其他任務上創建的延續任務)是設計可測試性時需要考慮的一個注意事項。這樣做時,通常的折衷適用。我嘗試在我的代碼創建任務時包含這樣的測試 - 這是我的代碼的一個重要行爲,需要進行測試。
我最終自己也得到了同樣的答案。很棒。在調用GC.Collect和GC.WaitForPendingFinalizers之前,有一些可能會完成任務,但在實踐中,我發現可能性太低以至於無所謂。 – anelson 2011-08-06 04:10:54
你確定這可以嗎?我只是嘗試了'Task.Run(Throw)'和'Task.Factory.StartNew(Throw)'在一個'int Throw(){throw new Exception(); },在任務上嘗試了一個'use()'範圍,嘗試了連續任務,並且根本沒有任何任務變量。即使嘗試使用Thread.Sleep()或使用ManualResetEvent確保任務完成並給系統一些時間來完成任務,該事件也不會引發給我。 – angularsen 2016-02-02 12:23:38
重複問題: http://stackoverflow.com/questions/21266137/test-for-unobserved-exceptions – angularsen 2016-02-02 12:30:54