如何使用NUnit(或可能使用其他框架)测试异步方法?

时间:2012-08-30 07:22:19

标签: .net unit-testing asynchronous nunit async-await

我有一个ASP.NET Web API应用程序,其ApiController具有异步方法,返回Task<>个对象并标有async个关键字。

public class MyApiController : ApiController
{
    public async Task<MyData> GetDataById(string id)
    {
        ...
    }
}

如何为ApiController的异步方法编写NUnit测试?如果我需要使用另一个测试框架,我也会对此开放。我对.NET单元测试一般都很陌生,所以我对学习最佳实践感兴趣。

5 个答案:

答案 0 :(得分:47)

截至今天(2014年7月2日),异步测试得到以下支持:

在前两个框架​​中,测试方法必须具有此签名:

[TestMethod]
public async Task MyTestMethod()
{
   ...
   var result = await objectUnderTest.TestedAsyncMethod(...);
   // Make assertions
}
除了那个签名之外,NUnit支持这个:

public async void MyTestMethod()

当然,在任何这些测试方法中,您都可以使用await来调用并等待异步方法。

如果您使用的是不支持异步测试方法的测试框架,那么,唯一的方法就是调用异步方法并等待它以任何常用方式运行:{{ 1}},使用await的任何常用等待方法,读取Result方法返回的Task<T>的{​​{1}}属性,依此类推。等待之后,你可以照常做所有的断言。例如,使用MSTest:

async

答案 1 :(得分:15)

在我看来,NUnit 2.6中没有内置支持来测试返回Tasks的异步方法。我现在能看到的最佳选择是使用Visual Studio自己的UnitTesting框架或xUnit.net as both support asynchronous tests

使用Visual Studio UnitTesting框架,我可以编写如下的异步测试:

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class TestAsyncMethods
{
    [TestMethod]
    public async Task TestGetBinBuildById()
    {
         ...
         var rslt = await obj.GetAsync();
         Assert.AreEqual(rslt, expected);
    }
}

答案 2 :(得分:6)

请记住,NUnit 2.6系列与之前的系列一样,是针对.NET 2.0框架而构建的。因此,在面向.NET 2.0的程序集中,NUnit只能执行您自己编写的相同内容。

具体来说,您无法将测试方法标记为 async ,并希望NUnit能够对其执行任何特殊操作。

但是,你可以

  • 针对您的测试使用.NET 4.5。 NUnit将单独运行它们 处理。
  • 在测试中使用等待等待调用的结果 async 方法。

如果这是你所希望的,那么上述任何一个都不会给你异步测试执行。在等待异步操作完成时,不会执行任何其他测试。

另一种选择是使用NUnitLite。 NUnitLite 0.8支持[Asynchronous]属性,允许在异步测试完成时继续进行其他测试。该属性的优点是它允许异步测试在.NET 2.0到4.0中运行

我们目前没有NUnitLite的.NET 4.5版本,但很快就会添加它,我们正在进行一项在该环境中使用[Asynchronous]可选的更改。目前,您可以轻松下载并重新编译.NET 4.5的源代码。

对于未来,请查看NUnit 3.0以完全支持异步方法,以及在多个线程或多个进程中一般并行执行测试。

答案 3 :(得分:3)

这实际上取决于他们在做什么。通常他们会依赖于提供Task<T>或类似内容的 else 。在这种情况下,您可能能够提供虚假的依赖关系,允许您以细粒度的方式控制所有这些。我有一个原型“时间机器”,它允许你在特定的人工时间完成预编程任务,然后移动时间并随时执行断言。你可能会发现blog post about it有用。正如我所说,它只是一个原型,并不适合所有场景 - 但它可能适合你。

Stephen Cleary还有一些关于单元测试的博客文章(12),采用略有不同的方法,以及您可能觉得有用的NuGet package

基本方法与正常方法相同:为您的方法提供不同的输入(和依赖性输出)并测试结果。使用异步实现这一点绝对比较棘手,但它是可行的。

答案 4 :(得分:3)

我正在将我的一些方法转换为async。让它与NUnit一起使用非常简单。

测试方法不能是异步的。但是我们仍然可以访问任务并行库的全部功能,我们不能直接在测试方法中使用await关键字。

在我的例子中,我有一个方法:

    public string SendUpdateRequestToPlayer(long playerId)

它在nUnit中测试过如下:

     string result = mgr.SendUpdateRequestToPlayer(player.Id.Value);
     Assert.AreEqual("Status update request sent", result);
     mocks.VerifyAll();

现在我已将方法SendUpdateRequestToPlayer更改为异步

      public async Task<string> SendUpdateRequestToPlayer(long playerId)

我只需将我的测试修改为Wait即可完成任务:

 Task<string> task = mgr.SendUpdateRequestToPlayer(player.Id.Value);
 task.Wait(); // The task runs to completion on a background thread
 Assert.AreEqual("Status update request sent", task.Result);
 mocks.VerifyAll();