如何使用Moq根据Id值模拟嵌套服务调用的不同响应
问题:如何用Moq根据参数Id返回不同结果?
我有如下调用语句:
var res = _serviceA.MethodA(() => _serviceB.MethodB(new ObjectA(){ Id = 10 }));
该语句在方法中被调用两次,响应会根据Id值变化,因此我需要设置Mock使其根据Id值返回不同对象。
当前Mock代码:
_serviceAMock.Setup(x => x.MethodA(It.IsAny<Func<ResponseObject>>())).Returns(responseOfTypeResponseObject);
我已能模拟MethodA并获取响应,但无法实现根据Id值返回不同结果,请问能否通过Moq实现该需求?若可以,具体如何操作?
测试类代码:
public class ClassToTest { private readonly IServiceA<int> _serviceA; private readonly IServiceB _serviceB; public ClassToTest(IServiceA<int> serviceA, IServiceB serviceB) { _serviceA = serviceA; _serviceB = serviceB; } public void MethodToTest() { var res = _serviceA.MethodA(() => _serviceB.MethodB(new ObjectA() { Id = 10 })); } }
支持对象代码:
public class ObjectA { public int Id { get; set; } } public interface IServiceB { int MethodB(ObjectA objectA); } public interface IServiceA<T> { T MethodA(Func<T> handler); }
解决方案
可以实现,推荐两种简洁的操作方式:
方式一:Mock ServiceB根据Id返回对应值,让ServiceA执行传入委托
这种方式贴合业务调用逻辑,是最常用的方案:
- 初始化Mock实例
var serviceBMock = new Mock<IServiceB>(); var serviceAMock = new Mock<IServiceA<int>>();
- 配置ServiceB的
MethodB,根据ObjectA.Id返回不同结果
// Id=10时返回100 serviceBMock.Setup(x => x.MethodB(It.Is<ObjectA>(o => o.Id == 10))) .Returns(100); // Id=20时返回200 serviceBMock.Setup(x => x.MethodB(It.Is<ObjectA>(o => o.Id == 20))) .Returns(200);
- 配置ServiceA的
MethodA,直接执行传入的委托并返回结果
serviceAMock.Setup(x => x.MethodA(It.IsAny<Func<int>>())) .Returns((Func<int> handler) => handler());
- 注入Mock实例到测试类执行测试
var testClass = new ClassToTest(serviceAMock.Object, serviceBMock.Object); testClass.MethodToTest();
当测试类调用MethodA时,会执行传入的_serviceB.MethodB委托,而ServiceB已被配置为根据Id返回对应值,最终就能得到符合预期的结果。
方式二:直接在ServiceA的Setup中解析委托参数(无需Mock ServiceB)
如果不想依赖ServiceB的Mock,可以直接在ServiceA的Setup中捕获传入的委托,解析出ObjectA.Id后返回对应值。不过这种方式兼容性较差,仅适用于固定结构的委托:
var serviceAMock = new Mock<IServiceA<int>>(); serviceAMock.Setup(x => x.MethodA(It.IsAny<Func<int>>())) .Returns((Func<int> handler) => { // 这里简化处理,实际需根据委托的IL结构解析出ObjectA的Id // 仅示例逻辑,复杂场景建议用方式一 var id = GetIdFromDelegate(handler); return id switch { 10 => 100, 20 => 200, _ => 0 }; }); // 辅助方法:解析委托获取Id(示例逻辑,需根据实际委托结构调整) private int GetIdFromDelegate(Func<int> handler) { // 此处可通过表达式树或IL解析获取ObjectA的Id值 // 示例仅模拟返回固定值,实际需实现解析逻辑 return 10; }
注意:方式二的解析逻辑依赖委托的固定结构,若业务代码中委托形式变化,解析会失效,因此优先推荐方式一。
内容的提问来源于stack exchange,提问作者Comraid
相关产品推荐
相关产品推荐

