I try to write a Unit-Test for a View Model, but i got stuck when trying to verify a ICommand calls a asynchronous method twice.
i use Moq for my dependencies. I set up the async Method like this.
this.communicationServiceFake
.Setup(x => x.WriteParameterAsync(It.IsAny<string>(), It.IsAny<object>()))
.ReturnsAsyncIncomplete();
The Extension ReturnsAsyncIncomplete does not return instantly at the await keyword, basically something like that found here: Async/Await and code coverage
I use a own TaskSheduler to ensure that the Methods are compete before the Task.Factory.StartNew returns.
Task.Factory.StartNew(() => viewModel.Command.Execute(null),
CancellationToken.None, TaskCreationOptions.None, new CurrentThreadTaskScheduler ());
Basically the CurrentThreadTaskScheduler comes from here: Wait until all Task finish in unit test and does look like this:
public class CurrentThreadTaskScheduler : TaskScheduler
{
protected override void QueueTask(Task task)
{
this.TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(Task task, bool wasPreviouslyQueued)
{
return this.TryExecuteTask(task);
}
protected override IEnumerable<Task> GetScheduledTasks()
{
yield break;
}
}
the Command does call the following code:
await this.communicationService.WriteParameterAsync("Parameter1", true);
await this.communicationService.WriteParameterAsync("Parameter2", true);
Then the verification:
this.communicationServiceFake
.Verify(t => t.WriteParameterAsync("Parameter1", true), Times.Once);
this.communicationServiceFake
.Verify(t => t.WriteParameterAsync("Parameter2", true), Times.Once);
sometimes it says the 2nd call did not happen. If i replace my Task.Factory.StartNew with a ThreadSleep to ensure everything finished, all works fine even thought it does note seem right to delay my unit tests unnecessarily.
Why does my CurrentThreadTaskScheduler allow the Task.Factory.StartNew to return before my Command.Execute finished?