单元测试复用模拟数据:Moq创建AssetIndexSummaryDto遇空引用异常
解决DTO测试假数据的空引用问题+优雅写法
问题根源:用Moq创建POCO是错误用法
Moq的核心作用是模拟接口、抽象类或带虚成员的类,用来隔离依赖。而AssetIndexSummaryDto作为普通POCO(无虚属性/方法),用Moq生成的Mock对象本质是代理类,即使调用SetupAllProperties(),未显式赋值的引用类型属性依然会返回null——当映射逻辑访问这些未初始化的属性时,就会触发NullReferenceException。
直接解决空引用:放弃Moq,改用正确的DTO实例化方式
1. 最简方案:直接实例化赋值
var testDto = new AssetIndexSummaryDto { Id = 1, Name = "测试资产索引", // 按需填充所有映射逻辑会用到的属性 };
2. 复用性方案:Builder模式封装
如果多个测试需要创建结构类似的DTO,写一个Builder类统一管理数据生成,避免重复复制粘贴:
public class AssetIndexSummaryDtoBuilder { // 设置默认值,减少重复赋值 private int _id = 1; private string _name = "默认资产索引"; private DateTime _createTime = DateTime.Now; // 链式修改属性 public AssetIndexSummaryDtoBuilder WithId(int id) { _id = id; return this; } public AssetIndexSummaryDtoBuilder WithName(string name) { _name = name; return this; } public AssetIndexSummaryDtoBuilder WithCreateTime(DateTime time) { _createTime = time; return this; } // 生成最终实例 public AssetIndexSummaryDto Build() { return new AssetIndexSummaryDto { Id = _id, Name = _name, CreateTime = _createTime // 其他属性按默认值或已修改的值填充 }; } }
测试中使用:
// 创建默认实例 var defaultDto = new AssetIndexSummaryDtoBuilder().Build(); // 创建自定义属性的实例 var customDto = new AssetIndexSummaryDtoBuilder() .WithId(100) .WithName("自定义索引") .Build();
3. 高效方案:用测试数据生成库
如果需要大量随机/多样化的测试数据,用AutoFixture或Bogus这类工具自动填充POCO:
AutoFixture示例
var fixture = new Fixture(); // 自动生成所有属性的有效值 var autoGeneratedDto = fixture.Create<AssetIndexSummaryDto>(); // 手动覆盖特定属性 autoGeneratedDto.Name = "手动修改名称";
Bogus示例(生成更真实的随机数据)
var faker = new Faker<AssetIndexSummaryDto>() .RuleFor(dto => dto.Id, f => f.Random.Int(1, 1000)) .RuleFor(dto => dto.Name, f => f.Commerce.ProductName()) .RuleFor(dto => dto.CreateTime, f => f.Date.Past()); var realisticDto = faker.Generate();
优雅管理测试假数据的原则
- 拒绝重复硬编码:把通用测试数据(比如边界值、默认值)抽成静态常量或方法。
- POCO用专门的工具生成:Moq留给依赖模拟,测试数据用Builder、AutoFixture/Bogus更合适。
- 单一职责:每个Builder/Factory只负责对应DTO/Entity的数据生成,维护更简单。
内容的提问来源于stack exchange,提问作者varde
相关产品推荐
相关产品推荐

