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

Moq返回配置问题:单元测试第二次执行返回错误数据

问题分析与解决方案

这个问题的核心原因是Moq在使用Returns(固定值)时,会缓存返回的引用类型实例,而你返回的List<Entity>是引用类型,第一次调用服务时,业务代码修改了这个List(通过AddRange),导致第二次调用时,Moq返回的还是被修改过的同一个实例。

具体来说:

  • 你的Setup代码中,每个Returns(Task.FromResult(new List<Entity> {...}))会在Setup执行时创建一个List实例,并把这个实例包装成Task缓存起来。
  • 第一次调用服务时,GetJsonFromApi(..., ENTITY_A)返回这个List实例,之后业务代码通过AddRange往这个List里添加了ENTITY_B和ENTITY_C的元素,导致这个List的元素数量变成了3。
  • 第二次调用服务时,GetJsonFromApi(..., ENTITY_A)依然返回这个已经被修改过的List,所以第一个调用返回3个对象,最终总数量是5。

解决方法

要避免这个问题,你需要让Moq每次调用时都返回一个新的List实例,这可以通过使用Returns的lambda重载实现(而不是传入固定的Task实例):

修改你的Setup代码,把Returns(Task.FromResult(...))改成Returns(() => Task.FromResult(...)),这样每次调用目标方法时,都会执行lambda表达式,创建一个全新的List实例:

_dataService.Setup(x => x.GetJsonFromApi(It.IsAny<string>(), API_KEY, ENTITY_A))
    .Returns(() => Task.FromResult(new List<Entity>() { new Entity { Forename = "first_name", Surname = "last_name", EntityType = ENTITY_A } }));
_dataService.Setup(x => x.GetJsonFromApi(It.IsAny<string>(), API_KEY, ENTITY_B))
    .Returns(() => Task.FromResult(new List<Entity>() { new Entity { Forename = "first_name", Surname = "last_name", EntityType = ENTITY_B } }));
_dataService.Setup(x => x.GetJsonFromApi(It.IsAny<string>(), API_KEY, ENTITY_C))
    .Returns(() => Task.FromResult(new List<Entity>() { new Entity { Forename = "first_name", Surname = "last_name", EntityType = ENTITY_C } }));

额外说明

如果你需要在某些场景下保留同一个实例(比如测试单例行为),这种缓存行为是有用的,但在你的测试场景中,由于业务代码会修改返回的集合,就必须确保每次调用都返回新的实例,避免不同测试执行之间的状态污染。

另外,如果你是在同一个测试方法中多次调用服务(比如测试锁定逻辑),除了修改Setup,也可以考虑在每次调用服务前重置Moq的状态(比如调用_dataService.Reset()),但这种方法不如使用lambda返回新实例简洁可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 07:32:30