2009-07-23 196 views
20

我在.NET平台上使用Xunit和NMock。 我正在测试一个方法是异步的表示模型。 该方法创建一个异步任务并执行它,以便该方法立即返回,并且需要检查的状态尚未准备好。有没有一种方法来单元测试异步方法?

我可以在不修改SUT的情况下设置标志,但这意味着我必须在while循环中检查标志,例如可能超时。

我有什么选择?

+0

.NET不具备条件变量? – jrockway 2009-07-23 21:50:29

+0

你想要测试什么? – 2009-07-23 22:00:08

+0

有复杂的解决方案,但如果它只是一个测试,那么循环/超时/标志选项没有任何问题。 – Ray 2009-07-24 08:19:10

回答

19

您的对象是否具有异步方法完成的任何种类的信号,例如事件?如果是这样的话,你可以用下面的办法:

[Test] 
public void CanTestAsync() 
{ 
    MyObject instance = new MyObject() 
    AutoResetEvent waitHandle = new AutoResetEvent(false); 
    // create and attach event handler for the "Finished" event 
    EventHandler eventHandler = delegate(object sender, EventArgs e) 
    { 
     waitHandle.Set(); // signal that the finished event was raised 
    } 
    instance.AsyncMethodFinished += eventHandler; 

    // call the async method 
    instance.CallAsyncMethod(); 

    // Wait until the event handler is invoked 
    if (!waitHandle.WaitOne(5000, false)) 
    { 
     Assert.Fail("Test timed out."); 
    } 
    instance.AsyncMethodFinished -= eventHandler;  
    Assert.AreEqual("expected", instance.ValueToCheck); 
} 
4

我的首选方法是模拟并注入实际的线程机制,以便在测试中它不是异步的。有些时候这是不可能的(如果方法的线程是框架的一部分,或者不在你的控制之下)。

如果你不能控制线程创建,那么等待线程以某种方式完成,或者是一个while循环,或者只是一个定时的等待,无论线程应该占用多长时间,并且如果状态为不在那里,因为反正花了太长时间。

46

只是觉得你可能想要在这方面的更新,因为#1答案实际上是建议一个较旧的模式来解决这个问题。

在.net 4.5 + xUnit 1.9或更高版本中,您可以简单地返回一个Task,并可以使用测试中的async关键字让xunit等待测试异步完成。

请参阅这篇文章xUnit.net 1.9

[Fact] 
public async Task MyAsyncUnitTest() 
{  
    // ... setup code here ...  
    var result = await CallMyAsyncApi(...);  
    // ... assertions here ... 
} 
相关问题