我如何告诉Moq返回一个任务?

我有一个接口声明

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()的代码。测试在这一行就失败了。我做错了什么?

219920 次浏览

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

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

更新2014-06-22

Moq 4.2有两个新的扩展方法来帮助实现这一点。

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


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

更新2016-05-05

正如Seth Flowers在其他的答案中提到的,ReturnsAsync仅适用于返回Task<T>的方法。对于只返回Task的方法,

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

可以使用。

这个答案所示,在。net 4.6中,这被简化为.Returns(Task.CompletedTask);,例如:

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

类似的问题

我有一个大致看起来像这样的界面:

Task DoSomething(int arg);

症状

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

修复

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

然而,你仍然可以在设置中使用.Returns(Task.FromResult(default(object))),允许测试通过。

你只需要在Callback之后添加.Returns(Task.FromResult(0));

例子:

mock.Setup(arg => arg.DoSomethingAsync())
.Callback(() => { <my code here> })
.Returns(Task.FromResult(0));
现在你也可以使用Talentsoft.Moq.SetupAsync包 https://github.com/TalentSoft/Moq.SetupAsync < / p >

根据这里找到的答案和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());