我有一个接口声明
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()的代码。测试在这一行就失败了。我做错了什么?
你的方法没有任何回调,所以没有理由使用. callback()。您可以使用. returns()和Task简单地返回一个带有所需值的Task。FromResult,例如:
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);
现在你也可以使用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());
感谢公认的答案,非常有用的解决方案。
我已经为我们的项目添加了两个扩展方法(Task和ValueTask),以使它更容易被习惯在所有异步设置上调用. returnsasync的人发现。
public static class MoqExtensions
{
public static IReturnsResult<TMock> ReturnsAsync<TMock>(this IReturns<TMock, Task> mock)
where TMock : class
{
return mock.Returns(Task.CompletedTask);
}
public static IReturnsResult<TMock> ReturnsAsync<TMock>(this IReturns<TMock, ValueTask> mock)
where TMock : class
{
return mock.Returns(ValueTask.CompletedTask);
}
}
可以这样调用:
mock.Setup(x => x.DoSomethingAsync())
.ReturnsAsync();