You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6中Mock DbSet<T>调用AsQueryable返回空列表的原因咨询

问题原因分析

你遇到的现象核心原因是:Moq模拟的DbSet对象,其IQueryable实现的执行逻辑存在缺陷,导致调用AsQueryable()后的查询无法正确获取测试数据;而显式让AsQueryable()返回原始测试数据的IQueryable时,能绕过这个缺陷。

具体细节

  1. AsQueryable()的本质
    AsQueryable()是System.Linq.Enumerable的扩展方法,当调用对象本身已经实现IQueryable<T>(比如DbSet),方法会直接返回该对象的IQueryable<T>实例,而非重新包装。

  2. 当前模拟逻辑的问题
    你的MockDbExtensions通过dbSetMock.As<IQueryable<T>>()设置了IQueryable<T>的Provider、Expression等成员,但配套的TestAsyncEnumerable类重写了IQueryable.Provider属性,返回的是TestAsyncQueryProvider<T>(this),而非使用原始测试数据的Provider。
    当调用AsQueryable().ToList()时,Queryable.ToList()会通过这个自定义Provider执行查询:

    • TestAsyncQueryProvider的CreateQuery方法返回TestAsyncEnumerable实例,该实例的Provider又指向自身,形成循环依赖。
    • 最终执行表达式时,TestAsyncEnumerable无法正确解析原始测试数据的表达式,导致返回空列表。
  3. 显式模拟AsQueryable的作用
    如果你直接让AsQueryable()返回原始的测试数据IQueryable<T>(比如testData),相当于绕过了Moq模拟的IQueryable<T>实现,直接使用List原生的IQueryable逻辑,自然能正确返回预期数据。

修复方案

方案1:修正TestAsyncEnumerable的Provider逻辑

移除TestAsyncEnumerable中自定义的IQueryable.Provider重写,让它使用父类EnumerableQuery<T>的原生Provider:

internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>
{
    public TestAsyncEnumerable(IEnumerable<T> enumerable)
        : base(enumerable)
    { }

    public TestAsyncEnumerable(Expression expression)
        : base(expression)
    { }

    public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
    {
        return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
    }
}

方案2:直接让AsQueryable返回原始测试数据

在MockDbSet方法中添加设置,让模拟的DbSet作为IQueryable时,AsQueryable()返回原始测试数据:

public static Mock<DbSet<T>> MockDbSet<T>(this IQueryable<T> testData) where T : class
{
    Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
    // 原有设置...
    dbSetMock.As<IQueryable<T>>().Setup(m => m.AsQueryable()).Returns(testData);
    return dbSetMock;
}

内容的提问来源于stack exchange,提问作者khachanthanh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:15:28