如何使用Moq返回未完成Task<List>以测试含Task.WhenAll的代码
问题原因
你之前的写法存在问题:直接通过new Task<List<SourceOneDto>>()创建的是未启动的冷任务,该任务永远不会进入完成状态,因此Task.WhenAll()会一直陷入等待,无法得到预期结果。
正确实现方式
根据你的场景可以选择以下三种实现方案:
方案1:返回已完成的Task(无需模拟异步延迟)
使用Task.FromResult()包裹返回结果,直接生成已完成状态的Task:
// 配置ReturnA的模拟返回 var mockReturnAResult = new List<SourceOneDto> { new SourceOneDto { Data = "模拟返回数据" } }; _sourceServiceMock.Setup(s => s.ReturnA()) .Returns(Task.FromResult(mockReturnAResult)); // 配置ReturnB的模拟返回 _sourceServiceMock.Setup(s => s.ReturnB()) .Returns(Task.FromResult(new List<SourceTwoDto>()));
方案2:使用Moq内置语法简化配置(Moq 4.16及以上版本支持)
直接调用ReturnsAsync()方法,Moq会自动帮你封装Task:
// 配置ReturnA的模拟返回 _sourceServiceMock.Setup(s => s.ReturnA()) .ReturnsAsync(new List<SourceOneDto> { new SourceOneDto { Data = "模拟返回数据" } }); // 配置ReturnB的模拟返回 _sourceServiceMock.Setup(s => s.ReturnB()) .ReturnsAsync(new List<SourceTwoDto>());
方案3:模拟带延迟的未完成Task(还原真实异步场景)
如果需要模拟和真实业务一致的、需要等待一段时间才完成的Task,可直接传入异步委托:
// 模拟ReturnA延迟1ms后返回结果,和你示例中的真实实现逻辑一致 _sourceServiceMock.Setup(s => s.ReturnA()) .Returns(async () => { await Task.Delay(1); return new List<SourceOneDto> { new SourceOneDto { Data = "模拟返回数据" } }; }); // 模拟ReturnB延迟2ms后返回结果 _sourceServiceMock.Setup(s => s.ReturnB()) .Returns(async () => { await Task.Delay(2); return new List<SourceTwoDto>(); });
注意事项
你示例代码中使用a.Result[0].Data获取结果的写法存在死锁风险,建议改为(await a)[0].Data的异步写法读取返回值。
内容的提问来源于stack exchange,提问作者Paul_87
相关产品推荐
相关产品推荐

