如何使用异步方法对ViewModel进行unit testing。

我不知道从哪里开始,但让我简要介绍一下我在哪里以及我想要实现的目标。 我对MVVM上的unit testing很陌生,并且很难测试我使用PRISM委托命令属性公开的命令。 我的委托命令调用必须等待的异步方法,以便我可以获得实际结果。 下面是一个asyc方法,由我想测试的方法调用。

async void GetTasksAsync() { this.SimpleTasks.Clear(); Func<IList> taskAction = () => { var result = this.dataService.GetTasks(); if (token.IsCancellationRequested) return null; return result; }; IsBusyTreeView = true; Task<IList> getTasksTask = Task<IList>.Factory.StartNew(taskAction, token); var l = await getTasksTask; // waits for getTasksTask if (l != null) { foreach (ISimpleTask t in l) { this.SimpleTasks.Add(t); // adds to ViewModel.SimpleTask } } } 

这里也是我的VM中的命令,它调用上面的异步方法

  this.GetTasksCommand = new DelegateCommand(this.GetTasks); void GetTasks() { GetTasksAsync(); } 

现在我的测试方法就像

  [TestMethod] public void Command_Test_GetTasksCommand() { MyViewModel.GetTaskCommand.Execute(); // this should populate ViewModel.SimpleTask Assert.IsTrue(MyBiewModel.SimpleTask != null) } 

目前我得到的是我的ViewModel.SimpleTask = null这是因为它不等待异步方法完成。 我知道堆栈溢出已经存在一些相关的主题,但我找不到与DelegateCommands相关的东西。

您的方法GetTasksAsync应返回一个Task,以便您可以实际等待它。

我在Channel9上特别推荐这一系列 ,解释你的问题。

只是要说清楚:只需将GetTasksAsync的签名更改为

 Task GetTasksAsync(); 

允许你这样做:

 var t = GetAsync(); t.Wait(); Assert(...); 

如果你真的想要在unit testing中测试命令而不是命令调用的实际方法,你可以使用ViewModel中的一个字段来存储任务(不是那么干净)或者通过类似描述的方式替换你的DelegateCommand。这篇文章: Awaitable DelegateCommand

更新:除了博客文章并考虑到你正在使用PRISM,你应该看看与PRISM在同一团队中的Project Kona 。 他们实际上实现了DelegateCommand来支持AsyncHandlers