I have a unit test (using MSTest) like so:
[TestMethod]
public void MyTest()
{
var viewModel = new MyViewModel();
viewModel.Run();
//Assert something here
}
Run is an async method that returns void.
Let's say Run
is implemented like so:
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()
, is itself an async method that returns some Task<T>
where T is the result my ViewModel is interested in.
My issue, is that my test is running the Run
method asynchronously, so the my assertions are called before the Run
methods completes. It is odd, b/c the finally block is never reached when I put a breakpoint, since the assertions fail. How can I keep the Run
method synchronous to be able to unit test it?
I have a unit test of myAsyncModelClass.LongRunningOperation()
also, but I merely call Task<T>.Wait()
since it returns a task. This makes it synchronous when unit testing.
Also, I would like to mention, Run()
is invoke by an ICommand magically by an MVVM framework. void
may or may not be a require return type, I will have to try it out.
Async methods need a context to "return to". Since MSTests run on the thread pool, by default the async methods all continue on a thread pool thread as well (and do not block the MSTest method).
Under the (C# Testing) Unit Testing
sample (in your Async CTP install directory), there's a type called GeneralThreadAffineContext
, which can be used as such:
[TestMethod]
public void MyTest()
{
MyViewModel viewModel = null;
GeneralThreadAffineContext.Run(() =>
{
viewModel = new MyViewModel();
viewModel.Run();
});
//Assert something here
}
There are also specific WPF and WinForms contexts, but the thread-affine context should work for general ViewModels (that don't make explicit use of Dispatcher
).
Update 2012-02-05: If you can change your ViewModel method to return Task
, then you have another option: the new AsyncUnitTests library. Install that NuGet package, change your TestClass
to AsyncTestClass
, and your async unit tests can be written much more naturally:
[TestMethod]
public async void MyTest()
{
MyViewModel viewModel = new MyViewModel();
await viewModel.Run();
//Assert something here
}
Update 2012-09-04: Visual Studio 2012 includes async
unit testing, so you don't need the AsyncUnitTests
library anymore:
[TestMethod]
public async Task MyTest()
{
MyViewModel viewModel = new MyViewModel();
await viewModel.Run();
//Assert something here
}