如何用Moq框架Mock泛型动态属性的Setup与Return?
解决Moq中Mock动态属性的问题
环境信息
- .NET Core 3.1
- PostgreSQL 14.2(64位,Visual C++ build 1914编译)
- EntityFramework.Functions 1.5.0
- Microsoft.EntityFrameworkCore.Design 5.0.17
- Microsoft.EntityFrameworkCore.Tools 5.0.17
- Npgsql.EntityFrameworkCore.PostgreSQL 5.0.10
问题场景
业务类JohnDoeClass的MaryDoeMethod方法依赖ITargetWrapper<dynamic>,其中targetWrapper.Data是动态类型,包含someDynamicMetaDataEntity属性,业务代码通过字典索引器访问该属性的字段。现在需要用Moq对这个动态依赖进行Mock,完成单元测试。
解决方案
Moq对动态类型的直接支持有限,我们可以通过创建动态模拟对象包装测试数据,再让ITargetWrapper<dynamic>.Data返回该对象来实现Mock。完整测试代码如下:
public class JohnDoeClassTests { [Fact] public void MaryDoeMethodTest_Valid() { // 1. 准备测试数据:用字典模拟业务代码中访问的dataset结构 var dataset = new Dictionary<string, object> { ["id"] = 3, ["fax_id"] = 7, ["fax_number"] = "416-949-9393", ["fax_location"] = "348 Rover Drive, New York, NY, USA", ["subject"] = "Tax Rebate info 2023" }; // 2. 创建动态对象,包含业务代码需要的someDynamicMetaDataEntity属性 dynamic data = new ExpandoObject(); data.someDynamicMetaDataEntity = dataset; // 3. 配置Moq,让ITargetWrapper<dynamic>的Data属性返回上述动态对象 var targetWrapperMock = new Mock<ITargetWrapper<dynamic>>(); targetWrapperMock.Setup(r => r.Data).Returns(data); // 4. 执行测试方法并验证结果 var johnDoe = new JohnDoeClass(); var result = johnDoe.MaryDoeMethod(targetWrapperMock.Object); // 示例断言:验证返回值是否符合预期 Assert.Equal(3, result.Id); Assert.Equal("416-949-9393", result.FaxNumber); } }
补充说明
- 因为业务代码用字典索引器访问
dataset字段,直接使用Dictionary<string, object>比ExpandoObject更贴合实际逻辑,还能避免动态属性名称的大小写匹配问题。 - 如果业务代码是通过
.访问动态属性(比如dataset.id),可以把dataset也改成ExpandoObject:dynamic dataset = new ExpandoObject(); dataset.id = 3; dataset.fax_id = 7; dataset.fax_number = "416-949-9393"; // ...其他属性设置 data.someDynamicMetaDataEntity = dataset;
内容的提问来源于stack exchange,提问作者crazyTech
相关产品推荐
相关产品推荐

