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

调用两次DbContext获取Moq模拟数据时数据消失问题排查

嘿,我帮你找到问题所在了!你遇到的第二次调用ToList()数据消失的情况,核心是Mock DbSet时枚举器的设置方式不对,和Moq的Returns机制直接相关。

问题根源:枚举器被复用导致二次遍历无数据

你的GetMockSet方法里,对GetEnumerator的Setup是这么写的:

mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(querable.GetEnumerator());

这里的问题在于:querable.GetEnumerator()会在Setup阶段就创建一个枚举器实例,Moq会把这个实例缓存起来,后续所有调用GetEnumerator()都会返回同一个对象。当你第一次调用ToList()时,这个枚举器会被完整遍历到末尾;第二次再调用ToList()时,你拿到的还是那个已经耗尽的枚举器,自然读不到任何数据。

Moq的Returns机制差异

这里得明确Moq中Returns的两种核心用法,这是解决问题的关键:

  • 直接传值(如Returns(querable.GetEnumerator())):值会在Setup时就计算完成并缓存,后续所有调用都返回同一个实例。
  • 传入lambda表达式(如Returns(() => querable.GetEnumerator())):每次调用目标方法时,都会执行lambda表达式,返回一个全新的实例。

你的场景需要每次调用GetEnumerator()都拿到一个新的枚举器,这样每次遍历都能从头读取模拟数据。

修复方案

修改GetMockSet里的GetEnumerator Setup代码,改用lambda表达式返回新的枚举器:

mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => querable.GetEnumerator());

这样每次调用GetEnumerator()都会生成一个新的枚举器实例,不管你调用多少次ToList()或者Count(),都能正常获取到那5条模拟员工数据。

额外说明:为什么Employees属性没出问题?

看你代码里对mockDb.SetupGet(i => i.Employees)用的是Returns(() => GetMockSet(Employees).Object)——这里用了lambda表达式,所以每次访问_context.Employees都会生成一个全新的MockDbSet实例,里面的枚举器也是新的,所以如果用_context.Employees.ToList()两次,不会出现数据消失的问题。但Set<Employee>()的Setup是直接返回一个固定的MockDbSet实例,所以才会暴露枚举器复用的问题。

内容的提问来源于stack exchange,提问作者Donald N. Mafa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:42:03