jds*_*epp 6 c# unit-testing moq mocking async-await
我试图模拟单元测试的复杂情况:
_mockController = new Mock<IController>();
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
.Callback<Func<Task>>(async f => await f.Invoke());
Run Code Online (Sandbox Code Playgroud)
哪里IController有一个void方法Interrupt(Func<Task>> f),排队一些工作要做.
我测试的对象会调用Interrupt(),我可以像这样验证调用:
_mockController.Verify(tc => tc.Interrupt(It.IsAny<Func<Task>>()), Times.Once);
Run Code Online (Sandbox Code Playgroud)
...但是当Func<Task>在回调中调用参数时,await关键字在以下方面不受尊重Task:测试的执行在Task完成之前继续(尽管await在回调中).这种情况的一个症状是await Task.Delay(1000)在Interrupt() Task参数中添加一个将通过的测试变成一个失败的测试.
这种行为是由于Task测试期间如何处理线程或s 的细微差别?或Moq的限制?我的测试方法有这个签名:
[Test]
public async Task Test_Name()
{
}
Run Code Online (Sandbox Code Playgroud)
Callback不能返回值,因此不应该用于执行异步代码(或需要返回值的同步代码).Callback是一种"注入点",您可以挂钩来检查传递给方法的参数,但不能修改它返回的内容.
如果你想要一个lambda模拟,你可以使用Returns:
_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
.Returns(async f => await f());
Run Code Online (Sandbox Code Playgroud)
(我假设Interrupt退货Task).
在任务完成之前继续执行测试(尽管在回调中等待).
是的,因为Callback无法返回一个值,所以它总是输入为Action/ Action<...>,所以你的asynclambda最终成为一个async void方法,带来了所有带来的问题(如我的MSDN文章中所述).
更新:
Interrupt()实际上是一个void方法:它的作用是对函数(参数)进行排队,直到IController可能会被打扰停止它正在做的事情.然后它调用函数 - 它返回一个任务 - 并等待该任务
你可以模仿那种行为,如果这样可行的话:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1409 次 |
| 最近记录: |