【问题标题】:Async callback on mocked object not awaiting模拟对象上的异步回调不等待
【发布时间】:2016-05-12 07:04:43
【问题描述】:

我试图模拟单元测试的复杂情况:

_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&lt;Task&gt;&gt; f),它将一些工作排​​队等待完成。

我的测试对象确实调用了Interrupt(),我可以像这样验证调用:

_mockController.Verify(tc => tc.Interrupt(It.IsAny<Func<Task>>()), Times.Once);

...但是当在回调中调用参数Func&lt;Task&gt; 时,await 关键字在Task 中不受尊重:在Task 完成之前继续执行测试(尽管@987654331 @ 在回调中)。这种情况的一个症状是在 Interrupt() Task 参数中添加 await Task.Delay(1000) 会将通过的测试变成失败的测试。

这种行为是否是由于测试期间线程或Tasks 处理方式的细微差别?还是起订量的限制?我的测试方法有这个签名:

[Test]
public async Task Test_Name()
{
}

【问题讨论】:

  • 我怀疑这是起订量的限制,但您必须向他们提出问题才能确定。
  • 我用 Moq 打开了this issue。我会更新他们的回复。
  • 我的解决方案是编写一个 IController 的存根实现,它基本上是一个自定义 Mock:它跟踪调用并在返回 Task 的方法中异步运行这些中断,这是关键。

标签: c# unit-testing mocking async-await moq


【解决方案1】:

Callback 不能返回值,因此不应用于执行异步代码(或需要返回值的同步代码)。 Callback 是一种“注入点”,您可以使用它来检查传递方法的参数,但不能修改它返回的内容。

如果你想要一个 lambda 模拟,你可以使用 Returns:

_mockController.Setup(tc => tc.Interrupt(It.IsAny<Func<Task>>()))
    .Returns(async f => await f());

(我假设Interrupt 返回Task)。

在任务完成之前继续执行测试(尽管在回调中等待)。

是的,因为Callback 不能返回值,所以它总是输入为Action/Action&lt;...&gt;,所以你的async lambda 最终成为async void 方法,带有all the problems that brings(如所述在我的 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

【讨论】:

  • Interrupt() 实际上是一个 void 方法:它所做的是将函数(参数)排队,直到 IController 可以停止它正在做的事情。然后它调用函数——它返回一个Task——和awaits 即Task。我明白你关于它在幕后变成async void 的意思,并且会进一步调查。
  • @jdslepp:用更符合这些语义的模拟代码更新了我的答案。
猜你喜欢
  • 2021-06-30
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2020-03-13
  • 2011-05-10
  • 2018-09-22
相关资源
最近更新 更多