将同步Moq模拟转换为异步

cap*_*aig 25 c# moq async-await

我正在努力将同步asp.net代码的主体转换为.net 4.5和新的异步语法.

我有很多看起来像的测试代码:

var retVal = new Foo(bar,baz);
_myMock.Setup(x => x.DoSomething(123)).Returns(retVal);
Run Code Online (Sandbox Code Playgroud)

当我从转换的DoSomething的签名Foo DoSomething()async Task<Foo> DoSomething(),我所有的测试代码已经被改写.我目前的解决方法是将原始代码转换为:

var retVal = new Foo(bar,baz);
_myMock.Setup(x => x.DoSomething(123))
   .Returns(new Task<Foo>(()=>retVal));
Run Code Online (Sandbox Code Playgroud)

这不是一个特别困难的转换,但是当我有数千个需要更新的测试时,这是乏味的.

我尝试使用一个名为ReturnsAsync的扩展方法来执行某些形式的m,但是我遇到了一些我无法确定的类型推理问题.是否有一种标准或更简单的方法来转换这种模拟以更好地处理异步方法?

svi*_*ick 35

首先,命名:基于任务的异步模式(TAP)表示所有异步和返回Task的方法都应该以.结尾命名Async.所以,你的方法应该被命名DoSomethingAsync.

其次,构造函数Task创建一个Task未启动的,你必须Start()手动.如果您的实际DoSomething方法也是如此,那么这也不会遵循TAP,这意味着您的代码将无法正常工作await.相反,你应该使用Task.Run(() => value),或者甚至更好Task.FromResult(value).

第三,如果你向我们展示你的代码不能正常工作会更好,这样我们就可以告诉你你在哪里犯了错误.

现在,ReturnsAsync()扩展方法的主体非常简单,但对我来说大部分工作都是找出正确的类型(特别是因为我不知道Moq).代码如下所示:

public static class MoqExtensions
{
    public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(
        this IReturns<TMock, Task<TResult>> setup, TResult value)
        where TMock : class
    {
        return setup.Returns(Task.FromResult(value));
    }
}
Run Code Online (Sandbox Code Playgroud)


Kev*_*zyk 21

Moq 4.2添加了一个ReturnsAsync()扩展方法,因此您不再需要添加自己的扩展方法.