这是我如何做到这一点:
[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