【问题标题】:How can I return IQueryable<TEntity> object from a mock object?如何从模拟对象返回 IQueryable<TEntity> 对象?
【发布时间】:2020-01-08 11:41:28
【问题描述】:

我试图告诉模拟对象_portalUserRepositoryMock 上的方法GetAll() 返回IQueryable&lt;TEntity&gt; 类型的对象。我知道它是这种类型,因为要测试的类中的方法返回这种类型。

我无法提出解决方案。 我看到了这个post,但在尝试将library 包含到我的项目中时出错。有关 Microsoft.EntityFrameworkCore 版本的一些信息 - 这导致了更多问题。

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

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

被测类像这样使用存储库:

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;
        }
    }

我收到此错误:

消息:System.InvalidOperationException:源的提供者 IQueryable 不实现 IAsyncQueryProvider。只有提供者 实现 IEntityQueryProvider 可用于实体框架 异步操作。

我认为我收到此错误是因为正在使用 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() 方法调用下得到了红色波浪线。所以代码不会编译。

【问题讨论】:

  • 您使用的是 .NET Framework 还是 .Net Core?
  • @user54287 这个问题正如您对FirstOrDefaultAsync 所怀疑的那样。该扩展期望可查询也从IDbAsyncQueryProvider 派生,以匹配模拟不会的异步EF。正如例外所述。
  • @user54287 - 如果List&lt;T&gt; 是内存列表中的硬编码,那么AsQueryable 将在框中工作。
  • @user54287 删除 .GetQueryable() 你不需要它。这看起来像是他们演示如何使用该库的示例之一
  • @user54287 您的假数据中是否包含与Where 中的谓词匹配的数据。请记住,如果没有元素,FirstOrDefault 将返回 null。如果数据不满足过滤器,您将默认返回 null。

标签: c# asynchronous .net-core entity-framework-core nsubstitute


【解决方案1】:

你不知道,IQueryable&lt;T&gt; 是实体框架/核心处理的实现细节。除非您的业务逻辑实际上创建了 IQueryable&lt;T&gt; 的实现,否则您希望返回一个模拟存根对象。

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

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

如果您返回 IQueryable&lt;T&gt; 的实例,您还将测试 EF 单元测试已经完成的实现。单元测试应该只测试单元范围内的代码。

【讨论】:

  • 他们正在使用NSubstitute
【解决方案2】:

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

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

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

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

FirstOrDefault 将返回 null。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多