25

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

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

var retVal = new Foo(bar,baz);
_myMock.Setup(x => x.DoSomething(123)).Returns(retVal);

当我将 DoSomething 的签名从 转换为 时Foo DoSomething()async Task<Foo> DoSomething()我的所有测试代码都必须重写。我目前的解决方法是将原始代码转换为:

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

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

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

4

2 回答 2

35

首先,命名:基于任务的异步模式 (TAP) 说所有异步且返回Tasks 的方法都应命名为以 . 结尾Async。所以,你的方法应该命名为DoSomethingAsync.

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

第三,如果您向我们展示您的代码运行不佳会更好,以便我们可以告诉您您在哪里犯了错误。

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

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));
    }
}
于 2012-08-23T13:19:19.550 回答
21

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

于 2014-02-26T12:28:00.013 回答