首页 > 解决方案 > 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 的说法,测试不需要调用 Wait()or Result,并且从Visual Studio 2015 开始不推荐使用旧的官方方式,开箱即用支持异步测试。

Stephen Cleary • https://stephencleary.com/ 11 个月前 (2017-11-03 12:22:06 pm) 如页面顶部的大红色横幅所示,此解决方案是为 VS2010 设计的。VS2015 可以很好地与开箱即用的异步任务单元测试一起工作。

我应该改变什么?

标签: c#async-awaitmoqxunit.net

解决方案


的使用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);
    });

推荐阅读