3

我有一个单元测试(使用 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可能是也可能不是需要返回类型,我将不得不尝试一下。

4

2 回答 2

15

异步方法需要一个上下文来“返回”。由于 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 上下文,但线程仿射上下文应该适用于一般 ViewModel(不明确使用Dispatcher)。

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

[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
}
于 2011-08-31T18:16:58.500 回答
3

由于 Visual Studio 2012 MSTest 支持异步测试方法。请记住,他们应该返回 Task 而不是 void:

[TestMethod]
public async Task MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}
于 2012-07-15T13:26:53.677 回答