Moq模拟Entity Framework Core的DbSet二次枚举返回null问题咨询
问题原因
你遇到的问题根源是IQueryable.GetEnumerator()方法的Mock配置错误:
- 你当前的配置写法
.Returns(table2List.GetEnumerator())会在Mock初始化阶段就一次性生成一个固定的枚举器实例,后续所有对GetEnumerator()的调用都会复用这同一个枚举器 - 枚举器是单向迭代的,第一次查询完成后枚举器的内部指针已经移动到集合末尾,第二次查询复用同一个枚举器自然读取不到任何元素,所以返回null
- 而
Count()断言能通过的原因是该方法优先走LINQ to Objects的长度优化逻辑,没有触发枚举器迭代。
修复方案
只需要修改GetEnumerator()的Mock配置,改为每次调用时都生成新的枚举器实例即可:
把原来的配置行:
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(table2List.GetEnumerator());
替换为带lambda表达式的重载,让每次调用都返回新的枚举器:
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(() => table2List.GetEnumerator());
补充说明
如果是EF Core 3.0+版本的模拟场景,还需要额外适配IAsyncEnumerable<T>接口的实现,避免异步查询时报错,适配代码如下:
table2DbSetMock.As<IAsyncEnumerable<Table2Model>>() .Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>())) .Returns(() => new TestAsyncEnumerator<Table2Model>(table2List.GetEnumerator()));
这里的TestAsyncEnumerator是自定义的异步枚举器实现,你可以根据项目需求自行实现或者引入相关测试辅助类库。
内容的提问来源于stack exchange,提问作者CodeMonkey
相关产品推荐
相关产品推荐

