【问题标题】:How can I tell Moq to return a Task?我如何告诉 Moq 返回任务?
【发布时间】:2014-02-10 18:36:15
【问题描述】:

我有一个接口声明

Task DoSomethingAsync();

我正在使用 MoqFramework 进行测试:

[TestMethod()]
public async Task MyAsyncTest()
{
   Mock<ISomeInterface> mock = new Mock<ISomeInterface>();
   mock.Setup(arg => arg.DoSomethingAsync()).Callback(() => { <my code here> });
   ...
}

然后在我的测试中,我执行调用await DoSomethingAsync() 的代码。并且测试在那条线上失败了。我做错了什么?

【问题讨论】:

  • 当你说那一行的测试错误时,它会产生什么错误?
  • @AlSki 可能是 NullReferenceException。如您所见here

标签: c# unit-testing task-parallel-library moq


【解决方案1】:

您的方法没有任何回调,因此没有理由使用.CallBack()。您可以使用.Returns()Task.FromResult 简单地返回具有所需值的任务,例如:

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.FromResult(someValue));

2014 年 6 月 22 日更新

Moq 4.2 有两种新的扩展方法可以帮助解决这个问题。

mock.Setup(arg=>arg.DoSomethingAsync())
    .ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .ThrowsAsync(new InvalidOperationException());

2016-05-05 更新

正如 Seth Flowers 在 other answer 中提到的那样,ReturnsAsync 仅适用于返回 Task&lt;T&gt; 的方法。对于只返回一个任务的方法,

.Returns(Task.FromResult(default(object)))

可以使用。

this answer 所示,在.NET 4.6 中这被简化为.Returns(Task.CompletedTask);,例如:

mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.CompletedTask);

【讨论】:

  • .Returns(Task.CompletedTask);这就是我的答案
  • 感谢您及时更新此答案,因为 Moq 框架已收到更新!
  • .Returns(Task.FromResult(default(object)) 在返回类型为 void 时效果很好。 .Returns(Task.FromResult(null as MyType)) 在预期返回类型为 null 时效果很好。
  • @JeremyRayBrown 正如我所解释的,在 .NET 4.6 中 default(object) 不再需要。 null as MyTypedefault(MyType) 相同,只要 MyType 是引用类型。
【解决方案2】:

类似问题

我的界面大致如下:

Task DoSomething(int arg);

症状

当我的被测服务awaited 调用DoSomething 时,我的单元测试失败。

修复

与接受的答案不同,在这种情况下,您无法在此方法的Setup() 上调用.ReturnsAsync(),因为该方法返回非泛型Task,而不是Task&lt;T&gt;

但是,您仍然可以在设置中使用.Returns(Task.FromResult(default(object))),从而通过测试。

【讨论】:

  • 只是想一想,如果您需要返回非通用任务(非 .net 4.6),我会考虑返回 Task.Delay(1) 作为返回任务的简单方法。你也可以通过增加时间参数来模仿工作。
【解决方案3】:

你只需要在回调后添加.Returns(Task.FromResult(0));即可。

例子:

mock.Setup(arg => arg.DoSomethingAsync())
    .Callback(() => { <my code here> })
    .Returns(Task.FromResult(0));

【讨论】:

    【解决方案4】:

    现在您还可以使用 Talentsoft.Moq.SetupAsync 包 https://github.com/TalentSoft/Moq.SetupAsync

    基于此处找到的答案和向 Moq 提出但尚未在此处实施的想法:https://github.com/moq/moq4/issues/384,大大简化了异步方法的设置

    在以前的响应中发现很少有使用 SetupAsync 扩展完成的示例:

    mock.SetupAsync(arg=>arg.DoSomethingAsync());
    mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
    mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-31
      • 2015-02-04
      • 2020-04-15
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多