如何从模拟对象中 return IQueryable<TEntity> 对象?

How can I return IQueryable<TEntity> object from a mock object?

我试图将模拟对象 _portalUserRepositoryMock 上的方法 GetAll() 告诉 return 类型 IQueryable<TEntity> 的对象。我知道是这种类型,因为class中的方法要测试return是这种类型。

我一直想不出解决办法。 我在我的项目中看到了这个 , but had errors trying to include the library。关于 Microsoft.EntityFrameworkCore 版本的问题 - 这导致了更多问题。

我为得到这个错误所做的是:

_portalUserRepositoryMock = Substitute.For<IPortalUserRepository>();
_portalUserRepositoryMock.GetAll().Returns(fakeQueryablePUser.AsQueryable());

测试中的 class 使用这样的存储库:

var portal = await _portalUserRepository.GetAll().Include(p => 
p.Portal).Where(p => p.UserId == user.Id && p.Portal.PortalType == 
dto.PortalType).FirstOrDefaultAsync();

GetAll()方法是:

        public IQueryable<TEntity> GetAll()
    {
        try
        {
            return DbContext.Set<TEntity>().AsNoTracking();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

我收到这个错误:

Message: System.InvalidOperationException : The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.

我想我收到此错误是因为正在使用 FirstOrDefaultAsync()。就是不知道怎么解决。

编辑: 我现在已经能够将 MockQueryable 库添加到我的测试项目中(通过使用版本 1.0.4 而不是最新的 1.1.0 )。我已经按照步骤操作了,如下图:

        var fakePortalUser = new PortalUser()
        {
            PortalId = new Guid()
        };

        var fakeQueryablePUser = new List<PortalUser>
        {
            fakePortalUser
        }.AsQueryable().BuildMock();

现在最后一步是使用 GetQueryable()。我在这里尝试使用:

_portalUserRepositoryMock.GetAll().GetQueryable().Returns(fakeQueryablePUser);

但是我在 GetQueryable() 方法调用下看到了红色波浪线。所以代码无法编译。

你不知道,IQueryable<T> 是由 Entity Framework / Core 处理的实现细节。除非您的业务逻辑实际上创建了 IQueryable<T> 的实现,否则您想要 return 模拟存根对象。

即(请注意,这使用库 Moq 来模拟对象,因为我不确定您使用的是什么,并且实现可能会有所不同。)

_mockedEntityQuery = new Mock<IQueryable<T>>();
_portalUserRepositoryMock = Substitute.For<IPortalUserRepository>();
_portalUserRepositoryMock.GetAll().Returns(_mockedEntityQuery.Object);

如果您 return IQueryable<T> 的一个实例,您还将测试该实现,该实现已由 EF 单元测试完成。单元测试应该只测试单元范围内的代码。

最初的问题与您怀疑的 FirstOrDefaultAsync 一样。该扩展期望可查询对象也有一个 IAsyncQueryProvider 以匹配默认情况下模拟不会出现的异步 EF。

删除 .GetQueryable(),因为您不需要它。该成员来自其中一个演示如何使用模拟库的示例。

还要确保假数据中的数据与 Where 中的谓词相匹配。

.Where(p => p.UserId == user.Id && p.Portal.PortalType == dto.PortalType)
如果没有要枚举的元素,

FirstOrDefault 将 return null

如果数据不满足过滤器,您将默认返回 null