How to Unit Test a ViewModel with async method.

async-await, c#, mvvm, prism, unit-testing

Solution

Your method GetTasksAsync should return a Task so you can actually wait for it.

I recommend this series on Channel9 an specially this episode explaining your problem.

Just to make is clear: Simply changing the signature of GetTasksAsync to

Task GetTasksAsync();

allows you to do this:

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

In case you really want to test the command in your unit tests and not the actually method called by the command you can use a field in your ViewModel to store the task to await (not so clean) or replace your DelegateCommand by something like described in this post: Awaitable DelegateCommand

Update: In addition to the blog post and considering you are using PRISM, you should have a look a Project Kona from the same team as PRISM. They actually implemented DelegateCommand to support AsyncHandlers

Problem

I am not sure where to start but let me give you a brief idea on where I am and what I want to achieve. I am quite new to Unit Testing on MVVM and having difficulty on testing the commands that I exposed using PRISM delegate command properties. My delegate commands calls async method that has to be waited so I can get the actual result. Below is an asyc method that is called by method that I wanted to test. ``` 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 } } } ``` also here is the command in my VM that calls the async method above ``` this.GetTasksCommand = new DelegateCommand(this.GetTasks); void GetTasks() { GetTasksAsync(); } ``` and now my Test Method goes like ``` [TestMethod] public void Command_Test_GetTasksCommand() { MyViewModel.GetTaskCommand.Execute(); // this should populate ViewModel.SimpleTask Assert.IsTrue(MyBiewModel.SimpleTask != null) } ``` Currently what I am getting is that my ViewModel.SimpleTask = null this is because it does not wait for the async method to finish. I understand there are some related topics to this already in stack overflow but I could not find something related to my DelegateCommands.

Original source

Related problems