异步CTP,单元测试ViewModel的异步方法

jon*_*ers 3 .net c# wpf mvvm async-ctp

我有一个单元测试(使用MSTest),如下所示:

[TestMethod]
public void MyTest()
{
    var viewModel = new MyViewModel();
    viewModel.Run();
    //Assert something here
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

myAsyncModelClass.LongRunningOperation(),它本身就是一个异步方法,它返回一些Task<T>地方,其中T是我的ViewModel感兴趣的结果.

我的问题是,我的测试是Run异步运行该方法,因此在Run方法完成之前调用我的断言.奇怪的是,当我放置一个断点时,b/c永远不会达到finally块,因为断言失败了.如何保持Run方法同步以便能够对其进行单元测试?

我也有单元测试myAsyncModelClass.LongRunningOperation(),但我只是打电话,Task<T>.Wait()因为它返回一个任务.这使得它在单元测试时同步.

另外,我想提一下,Run()由一个MVVM框架神奇地调用ICommand. void可能会或可能不是要求退货类型,我将不得不尝试.

Ste*_*ary 15

异步方法需要一个"返回"的上下文.由于MSTests在线程池上运行,因此默认情况下,异步方法也在线程池线程上继续(并且不阻止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
}
Run Code Online (Sandbox Code Playgroud)

还有特定的WPF和WinForms上下文,但线程仿射上下文应该适用于一般的ViewModel(没有明确使用Dispatcher).

更新2012-02-05:如果您可以更改ViewModel方法以返回Task,那么您还有另一个选项:新的AsyncUnitTests库.安装NuGet包,更改你TestClassAsyncTestClass,你的异步单元测试可以更自然地编写:

[TestMethod]
public async void MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}
Run Code Online (Sandbox Code Playgroud)

更新2012-09-04: Visual Studio 2012包含async单元测试,因此您不再需要该AsyncUnitTests库:

[TestMethod]
public async Task MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}
Run Code Online (Sandbox Code Playgroud)