我尝试为视图模型编写单元测试,但在尝试验证 ICommand 调用异步方法两次时遇到了困难。
我使用 Moq 作为我的依赖项。
我像这样设置了异步方法。
this.communicationServiceFake
.Setup(x => x.WriteParameterAsync(It.IsAny<string>(), It.IsAny<object>()))
.ReturnsAsyncIncomplete();
扩展 ReturnsAsyncIncomplete 不会在 wait 关键字处立即返回,基本上类似于此处找到的内容:Async/Await 和代码覆盖率 http://bernhard-richter.blogspot.co.at/2014/09/asyncawait-and-code-coverage.html
我使用自己的 TaskSheduler 来确保方法在 Task.Factory.StartNew 返回之前完成。
Task.Factory.StartNew(() => viewModel.Command.Execute(null),
CancellationToken.None, TaskCreationOptions.None, new CurrentThreadTaskScheduler ());
基本上 CurrentThreadTaskScheduler 来自这里:等待单元测试中所有任务完成 https://stackoverflow.com/questions/17844182/wait-until-all-task-finish-in-unit-test看起来确实像这样:
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;
}
}
该命令确实调用了以下代码:
await this.communicationService.WriteParameterAsync("Parameter1", true);
await this.communicationService.WriteParameterAsync("Parameter2", true);
然后验证:
this.communicationServiceFake
.Verify(t => t.WriteParameterAsync("Parameter1", true), Times.Once);
this.communicationServiceFake
.Verify(t => t.WriteParameterAsync("Parameter2", true), Times.Once);
有时它说第二个电话没有发生。
如果我用 ThreadSleep 替换我的 Task.Factory.StartNew 以确保一切都完成,那么即使不必要地延迟我的单元测试似乎是正确的,一切都可以正常工作。
为什么我的 CurrentThreadTaskScheduler 允许 Task.Factory.StartNew 在 Command.Execute 完成之前返回?