_mockController = new Mock<IController>(); _mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>())) .Callback<Func<Task>>(async f => await f.Invoke());
IController有一个void方法Interrupt(Func< Task>> f),它将一些工作排队.
我正在测试的对象会调用Interrupt(),我可以像这样验证调用:
_mockController.Verify(tc => tc.Interrupt(It.IsAny<Func<Task>>()),Times.Once);
…但是当参数Func< Task>在回调中调用,在任务中不遵守await关键字:在任务完成之前继续执行测试(尽管在回调中等待).其中一个症状是在Interrupt()Task参数中添加await Task.Delay(1000)会将通过的测试转换为失败的测试.
这种行为是由于测试期间如何处理线程或任务的细微差别?或Moq的限制?我的测试方法有这个签名:
[Test] public async Task Test_Name() { }
解决方法
如果你想要一个lambda模拟,你可以使用返回:
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>())) .Returns(async f => await f());
(我假设中断返回任务).
the execution of the test continues before the Task finishes (despite the await in the callback).
是的,因为Callback不能返回值,所以它总是输入为Action / Action< ...>,所以你的异步lambda最终是一个异步void方法,有all the problems that brings(如我的MSDN文章中所述).
更新:
Interrupt() is actually a void method: what it does is queue the function (the argument) until the IController can be bothered to stop what it is doing. Then it invokes the function–which returns a Task–and awaits that Task
你可以模仿那种行为,如果这样可行的话:
List<Func<Task>> queue = new List<Func<Task>>(); _mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>())) .Callback<Func<Task>>(f => queue.Add(f)); ... // Code that calls Interrupt // Start all queued tasks and wait for them to complete. await Task.WhenAll(queue.Select(f => f())); ... // Assert / Verify