异步CTP,对ViewModel's异步方法进行单元测试

本文关键字:异步方法 单元测试 CTP ViewModel 异步 | 更新日期: 2023-09-27 18:07:14

我有一个像这样的单元测试(使用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最后块从来没有到达当我放置一个断点,因为断言失败。我如何保持Run方法同步,以便能够对其进行单元测试?

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

另外,我想提到的是,Run()是由一个iccommand通过MVVM框架神奇地调用的。void可能是也可能不是一个要求返回类型,我将不得不尝试一下。

异步CTP,对ViewModel's异步方法进行单元测试

异步方法需要一个上下文来"返回"。由于MSTest在线程池上运行,默认情况下,异步方法也都在线程池线程上继续运行(并且不会阻塞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上下文,但是线程仿射上下文应该适用于一般的ViewModels(不显式使用Dispatcher)。

更新2012-02-05:如果你可以改变你的ViewModel方法返回Task,那么你有另一个选择:新的AsyncUnitTests库。安装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
}

从Visual Studio 2012开始,MSTest支持异步测试方法。只要记住它们应该返回Task而不是void:

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