2011-08-31 173 views
3

我有一个单元测试(使用MSTest的)像这样:异步CTP,单元测试视图模型的异步方法

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

润返回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方法完成之前调用。奇怪的是,当我放置一个断点时,finally块永远不会到达,因为断言失败。我如何保持Run方法同步以便能够对其进行单元测试?

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

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

+0

嗨 - 我与C#-async(杀了我的VS安装),但如果它是一个异步函数可以调用运行没有经验? F#有一些类似的构造,但如果你试图调用一个asycn对象,那么你会得到一个编译错误。 - 无论如何,你为什么不把这个包装成一个Task并等待它(或者在你的测试中等待)? – Carsten

+0

我会返回一个任务,但是这个方法也是通过一个绑定到一个ICommand的MVVM框架来调用的。我不相信我的代码会在我的应用程序中执行,如果我做出这样的改变。 – jonathanpeppers

回答

14

异步方法需要上下文才能“返回”。由于MSTests在线程池上运行,所以默认情况下,异步方法也都在线程池线程上继续运行(并且不要阻塞MSTest方法)。

(C# Testing) Unit Testing样品(在异步CTP的安装目录),有一个名为GeneralThreadAffineContext类型,它可以被用作这样的:

[TestMethod] 
public void MyTest() 
{ 
    MyViewModel viewModel = null; 
    GeneralThreadAffineContext.Run(() => 
    { 
    viewModel = new MyViewModel(); 
    viewModel.Run(); 
    }); 
    //Assert something here 
} 

也有特定的WPF和WinForms上下文,但thread-仿射上下文应适用于一般ViewModel(不明确使用Dispatcher)。

更新2012-02-05:如果你可以改变你的视图模型方法返回Task,那么你有另一种选择:新AsyncUnitTests library。安装NuGet包,改变你的TestClassAsyncTestClass,你的异步单元测试可以更自然地写着:

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

更新2012年9月4日:的Visual Studio 2012包括async单元测试,所以你不要“T需要AsyncUnitTests库了:

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

对不起,我原来的代码有一个错误。它现在已经更新了。 –

+0

这很好。然而,我想我要构建自己的'GeneralThreadAffineContext'实现。 – jonathanpeppers

+0

如果您有兴趣,我已经发布了我的名为'AsyncContext'的Nito.AsyncEx库[的一部分](http://nitoasyncex.codeplex.com/wikipage?title=AsyncContext)。 –

3

由于的Visual Studio 2012 MSTest的支持异步测试方法。只是remeber他们应该返回工作,而不是无效:

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