[英]xUnit test hangs/deadlocks when calling method with anonymous Async method
我有一个始终挂起/死锁的xUnit(2.1.0)测试。 为了清楚和保密起见,此处更改了带有类/方法名称的代码:
[Fact]
public void DocumentModificationTest()
{
Exception ex = null;
using (TestDependency testDependency = new TestDependency())
{
TestDependencyDocument testDependencyDoc = testDependency.Document;
MockTestDependency fakeDependency = new MockTestDependency();
try
{
DoStuffToTheDocument(testDependencyDoc, "fileName.doc", fakeDependency);
}
catch (Exception e)
{
ex = e;
}
}
Assert.Null(ex);
}
如果我设置一个断点并逐步执行,直到断言为止,我可以看到ex为空,并且测试应该通过并完成,但是它挂起了,我从没有在赛跑者身上看到“测试成功”。
这是DoStuffToTheDocument的样子:
public static void DoStuffToTheDocument(TestDependencyDocument document, string pFileName, MockTestDependency pContainer)
{
pContainer.CheckInTheDocFirst(async () =>
{
//check some stuff
//test returns early here
//check other stuff(test never gets here)
//await method (thus the async anonymous method)
});
}
最后是CheckInTheDocFirst的样子:
public void CheckInTheDocFirst(Action pConfirmAction)
{
pConfirmAction(); //since this is a method in a mock class only used for testing we just call the action
}
任何想法在这里发生了什么? 我的async-await范例是否有某些东西导致该测试挂起?
事实证明,这是由xUnit中的异步void测试方法支持引起的问题: https : //github.com/xunit/xunit/issues/866#issuecomment-223477634
虽然您确实应该一直进行异步处理,但有时出于互操作性考虑,这是不可行的。 您不能总是更改正在使用的所有内容的签名。
但是,关于您的断言要注意的一件事是,即使异步void方法(在这种情况下为lambda)中引发了异常,它也将始终证明是正确的。 这是因为异步void的异常处理不同 :
异步void方法具有不同的错误处理语义。 从异步Task或异步Task方法抛出异常时,将捕获该异常并将其放置在Task对象上。 使用异步void方法时,没有Task对象,因此从异步void方法抛出的任何异常都将直接在启动异步void方法时处于活动状态的SynchronizationContext上引发。 图2说明了从异步void方法引发的异常不能自然地捕获。
当您具有异步功能时,您实际上应该一直处于异步状态。 否则,您将遇到同步上下文被阻止的问题,这将导致锁定。
pContainer.CheckInTheDocFirst应该是异步的,并返回一个Task(因为它采用了一个异步函数,该函数返回Task对象)。
DoStuffToDocument应该是一个返回Task的异步函数,因为它调用了异步函数。
最后,测试本身也应该是一个返回任务的异步方法。
如果您一直在堆栈上运行异步,那么我认为您会发现一切正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.