从未在最小起订量中调用的模拟异步方法

Mocked async method never called in Moq

我有一个数据库存储库接口:

public interface IDbRepository
{
  Task<T> GetDataAsync<T>(Func<T, bool> filter = null) where T : class;
}

我有以下夹具:

private List<Status> statusList = new List<Status> {
      new Status { Name="Status A"},
      new Status { Name="Status B"}
    };

var repositoryMock = new Mock<IDbRepository>();
Func<Status, bool> filter = It.IsAny<Func<Status, bool>>();
repositoryMock.Setup(repository => repository.GetDataAsync(filter))
  .ReturnsAsync(
  () =>
  {
    //NEVER CALLED
    if (filter == null)
      return statusList.FirstOrDefault();
    return statusList.FirstOrDefault(filter);
  });

我使用以下测试:

[Fact]
public async Task Repository_GetDataAsync_Filter()
{
  var repository = repositoryTestFixture.Ioc.Resolve<IDbRepository>();
  Func<Status, bool> filter = stat => stat.Name == "Status A";
  var res = await repository.GetDataAsync(filter);
  //await task1.ContinueWith(ctask => Assert.NotNull(ctask.Result));
  Assert.NotNull(res); //ALWAYS NULL!!!
}

我尝试调试,但该方法从未调用过,所以我总是得到一个失败的测试。

根据@Stephen Cleary 的说法,不需要测试 to call Wait() or Result, and the old official way 自 Visual Studio 2015 年起已弃用,开箱即用地支持异步测试。

Stephen Cleary • https://stephencleary.com/ 11 months ago (2017-11-03 12:22:06 pm) As noted in the big red banner at the top of the page, this solution was designed for VS2010. VS2015 works fine with async Task unit tests out of the box.

我应该改变什么?

It.IsAny<>() 的使用不准确。它只能直接在 Setup 表达式中使用。不在变量中。

当参数不匹配时,不会调用模拟。因此你得到空值。

访问 ReturnAsync 委托中传递的参数

var repositoryMock = new Mock<IDbRepository>();
repositoryMock
    .Setup(repository => repository.GetDataAsync(It.IsAny<Func<Status, bool>>()))
    .ReturnsAsync((Func<Status, bool> filter) => {//<-- grab passed argument here
        if (filter == null)
            return statusList.FirstOrDefault();
        return statusList.FirstOrDefault(filter);
    });

我认为这里的问题是由于您的 filter 局部变量引起的。通过创建一个不是表达式的变量,您实际上是在执行 It.IsAny 调用并返回 null。可以想象,null 只会匹配 null 函数,这就是为什么您看不到 ReturnsAsync 被命中的原因。

请尝试内联该变量或将其类型更改为 Expression<Func<Status, bool>> 并查看是否按预期工作。

您必须始终记住,模拟设置是使用表达式完成的,因此通常 It.IsX 调用本身从不执行,只是作为表达式树进行分析和比较。