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

如何用Moq/Nunit模拟Marten.IDocumentSession的ToListAsync查询?

模拟IDocumentSession的ToListAsync扩展方法报错的解决办法

问题场景

要测试的业务代码:

IReadOnlyList<Student> students = await _session
    .Query<Student>()
    .Where(x => x.ClassId == classId)
    .ToListAsync(cancellationToken);

尝试的Mock代码:

private Mock<IDocumentSession> _sessionMock = new Mock<IDocumentSession>();
...
_sessionMock
    .Setup(x => x
        .Query<Students>()
        .Where(y => y.ClassId == classId)
        .ToListAsync(CancellationToken.None))
    .ReturnsAsync(new List<Students>());       

遇到的错误:

System.NotSupportedException : Unsupported expression: ... => ....ToListAsync(CancellationToken.None)
Extension methods (here: QueryableExtensions.ToListAsync) may not be used in setup / verification expressions.

可行解决办法

Moq无法直接模拟扩展方法(ToListAsync、Where都属于LINQ扩展方法),核心解决思路是:MockIDocumentSession的Query<T>基础方法,让它返回预先构造好的IQueryable<Student>集合,后续的LINQ操作会自动在这个内存集合上执行,无需单独Mock扩展方法。

具体实现步骤

  1. 准备测试用的学生数据集,可提前包含符合和不符合筛选条件的数据,用于验证逻辑
var testStudents = new List<Student>
{
    new Student { ClassId = classId, Id = 1 },
    new Student { ClassId = classId, Id = 2 },
    new Student { ClassId = Guid.NewGuid(), Id = 3 } // 不符合条件的测试数据
}.AsQueryable();
  1. MockQuery<Student>()方法,返回上述的IQueryable集合
_sessionMock
    .Setup(s => s.Query<Student>())
    .Returns(testStudents);
  1. 执行测试并验证结果
    此时业务代码调用Query<Student>().Where(...).ToListAsync()时,会先获取Mock的IQueryable集合,自动执行Where筛选,再通过ToListAsync返回符合条件的结果,完全模拟真实逻辑。

进阶:验证筛选条件(可选)

如果需要确保业务代码确实使用了正确的ClassId进行筛选,可以通过验证最终返回的结果是否符合预期,或者针对支持表达式参数的Query重载进行Mock:

_sessionMock
    .Setup(s => s.Query<Student>(It.IsAny<Expression<Func<Student, bool>>>()))
    .Returns((Expression<Func<Student, bool>> filter) => 
        testStudents.Where(filter).AsQueryable());

这种方式可以确保传入的筛选表达式被正确应用,不过更多时候,通过验证最终返回的学生列表是否匹配预期,就能间接确认筛选逻辑的正确性。

注意事项

  • 必须将测试集合转换为IQueryable(调用AsQueryable()),因为IDocumentSession.Query<T>返回的是IQueryable<T>,这样后续的LINQ扩展方法才会走Queryable的实现,和真实场景一致。
  • 如果业务代码包含更复杂的查询(如Include、OrderBy),同样适用此思路:MockQuery<T>返回包含所需关联数据、排序后的IQueryable集合,后续扩展方法会自动在内存中执行。

内容的提问来源于stack exchange,提问作者Adil H. Raza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:01:42