如何使用异步方法对ViewModel进行单元测试.

Jep*_*ner 5 c# unit-testing prism mvvm async-await

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

 async void GetTasksAsync()
        {
            this.SimpleTasks.Clear();
            Func<IList<ISimpleTask>> taskAction = () =>
                {
                    var result = this.dataService.GetTasks();
                    if (token.IsCancellationRequested)
                        return null;
                    return result;
                };
            IsBusyTreeView = true;

            Task<IList<ISimpleTask>> getTasksTask = Task<IList<ISimpleTask>>.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
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

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

  this.GetTasksCommand = new DelegateCommand(this.GetTasks);
      void GetTasks()
        {
                GetTasksAsync();
        }
Run Code Online (Sandbox Code Playgroud)

现在我的测试方法就像

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

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

Jul*_*ien 9

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

我在Channel9上推荐这个系列,特别是这一集解释你的问题.

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

Task GetTasksAsync();
Run Code Online (Sandbox Code Playgroud)

允许你这样做:

var t = GetAsync();
t.Wait();
Assert(...);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 或者甚至更好,这允许您使用`async Task`单元测试并执行`await GetTasksAsync()`. (3认同)