我有一个单元测试(使用MSTest),如下所示:
[TestMethod]
public void MyTest()
{
var viewModel = new MyViewModel();
viewModel.Run();
//Assert something here
}
Run是一个返回void的异步方法。
假设Run
的实现方式如此:
public async void Run()
{
//Show a busy indicator here
try
{
var result = await myAsyncModelClass.LongRunningOperation();
//Use the results here
}
finally
{
//Hide the busy indicator here
}
}
myAsyncModelClass.LongRunningOperation()
,本身就是一个异步方法,返回一些Task<T>
,其中T是我的ViewModel感兴趣的结果。
我的问题是,我的测试是异步运行Run
方法,因此在Run
方法完成之前调用我的断言。奇怪的是,当我放置一个断点时,b / c永远不会达到finally块,因为断言失败了。如何使Run
方法保持同步以便对其进行单元测试?
我也有myAsyncModelClass.LongRunningOperation()
的单元测试,但我只是调用Task<T>.Wait()
,因为它返回一个任务。这使得它在单元测试时同步。
另外,我想提一下,Run()
由一个MVVM框架神奇地由ICommand调用。 void
可能是也可能不是要求退货类型,我将不得不尝试。
答案 0 :(得分:15)
异步方法需要一个“返回”的上下文。由于MSTests在线程池上运行,因此默认情况下async方法也都在线程池线程上继续(并且不阻塞MSTest方法)。
在(C# Testing) Unit Testing
示例下(在您的Async CTP安装目录中),有一个名为GeneralThreadAffineContext
的类型,可以这样使用:
[TestMethod]
public void MyTest()
{
MyViewModel viewModel = null;
GeneralThreadAffineContext.Run(() =>
{
viewModel = new MyViewModel();
viewModel.Run();
});
//Assert something here
}
还有特定的WPF和WinForms上下文,但线程仿射上下文应该适用于一般的ViewModel(不明确使用Dispatcher
)。
更新2012-02-05:如果您可以更改ViewModel方法以返回Task
,那么您还有另一个选项:新AsyncUnitTests library。安装NuGet包,将TestClass
更改为AsyncTestClass
,您的异步单元测试可以更自然地编写:
[TestMethod]
public async void MyTest()
{
MyViewModel viewModel = new MyViewModel();
await viewModel.Run();
//Assert something here
}
更新2012-09-04: Visual Studio 2012包含async
单元测试,因此您不再需要AsyncUnitTests
库了:
[TestMethod]
public async Task MyTest()
{
MyViewModel viewModel = new MyViewModel();
await viewModel.Run();
//Assert something here
}
答案 1 :(得分:3)
由于Visual Studio 2012 MSTest支持异步测试方法。只记得他们应该返回Task而不是void:
[TestMethod]
public async Task MyTest()
{
MyViewModel viewModel = new MyViewModel();
await viewModel.Run();
//Assert something here
}