我有一个ASP.NET Web API应用程序,其ApiController具有异步方法,返回Task<>
个对象并标有async
个关键字。
public class MyApiController : ApiController
{
public async Task<MyData> GetDataById(string id)
{
...
}
}
如何为ApiController的异步方法编写NUnit测试?如果我需要使用另一个测试框架,我也会对此开放。我对.NET单元测试一般都很陌生,所以我对学习最佳实践感兴趣。
答案 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能够对其执行任何特殊操作。
但是,你可以
如果这是你所希望的,那么上述任何一个都不会给你异步测试执行。在等待异步操作完成时,不会执行任何其他测试。
另一种选择是使用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还有一些关于单元测试的博客文章(1,2),采用略有不同的方法,以及您可能觉得有用的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();