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

C# 如何使用异步方法对ViewModel进行单元测试。,c#,unit-testing,mvvm,prism,async-await,C#,Unit Testing,Mvvm,Prism,Async Await,我不知道从哪里开始,但让我给你一个简单的想法,我在哪里,我想实现什么。我对MVVM上的单元测试非常陌生,在测试我使用PRISM委托命令属性公开的命令时遇到困难。 我的委托命令调用异步方法,该方法必须等待,以便获得实际结果。下面是我想测试的方法调用的asyc方法 async void GetTasksAsync() { this.SimpleTasks.Clear(); Func<IList<ISimpleTask>

我不知道从哪里开始,但让我给你一个简单的想法,我在哪里,我想实现什么。我对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
                }
            }
        }
现在我的测试方法是

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

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

您的方法GetTasksAsync应该返回一个任务,以便您可以实际等待它

我建议在第九频道特别解释你的问题

只是想说明一下:只需将GetTasksAsync的签名更改为

Task GetTasksAsync();
允许您执行以下操作:

var t = GetAsync();
t.Wait();
Assert(...);
如果您确实希望在单元测试中测试该命令,而不是该命令调用的实际方法,您可以使用ViewModel中的一个字段来存储要等待的任务(不太干净),或者用本文中描述的内容替换DelegateCommand:


更新:除了这篇博文,考虑到你正在使用PRISM,你应该看看PRISM所在的团队。它们实际上实现了

甚至更好,这允许您使用
异步任务
单元测试并执行
等待GetTasksAsync()
。感谢您的回答。但是,此GetTasksAsync()是我的Viewmodel中的一个私有方法,不希望公开给我的项目中的任何其他对象,并且仅由代理调用。话虽如此,我只是在测试公共方法。这些代理将公开。引入另一个领域可能是一条路,但你是对的,这将是肮脏的。我将查看您发送给我的等待代理命令链接,看看它是否有用。更新:我实施了您的上述答案,因为我还无法为解决方案编制其他备选方案,例如等待代理命令。实现这一点意味着我将我的私有方法更改为public(这有味道!),现在我的问题是,当使用t.Wait()调用GetTaskAsync()时,这个抛出InnerException={“这种类型的CollectionView不支持从不同于Dispatcher线程的线程对其SourceCollection进行更改。”}。这是因为它从另一个线程将项目添加到我的集合中。有什么想法吗?在.NET 4.5中,您可以使用BindingOperations.EnableCollectionsSynchronization方法(查看MSDN或本文),谢谢您的回答。我会把你的回答作为这个问题的答案,因为我并没有当场问到我真正需要什么,因为在这段时间里我真的不知道。作为更新,我将这个新问题作为后续问题发布到这篇文章中。
var t = GetAsync();
t.Wait();
Assert(...);