如何用AutoFixture自定义含Usage集合的Report测试数据?
使用AutoFixture生成符合要求的Report实例
定义的实体类
internal sealed class Report { public string Name { get; set; } public List<Usage> Usage { get; set; } } internal sealed class Usage { public DateTime DateTime { get; set; } public int Count { get; set; } }
需求说明
- 生成多组
Report实例 - 每个
Report包含15到30个Usage对象 - 每个
Usage的DateTime为过去30天内的不同日期
解决方案
方案1:直接定制Report生成逻辑(快速实现)
通过Fixture.Customize方法直接定义Report的Usage集合生成规则,适合简单场景:
var fixture = new Fixture(); var random = new Random(); // 定制Report的Usage集合生成逻辑 fixture.Customize<Report>(composer => composer .With(r => r.Usage, () => { // 随机生成15-30之间的Usage数量 var usageCount = random.Next(15, 31); // 生成过去30天的连续日期(含今天) var startDate = DateTime.Today.AddDays(-29); // 取对应数量的日期并打乱顺序,保证不重复 var uniqueDates = Enumerable.Range(0, usageCount) .Select(i => startDate.AddDays(i)) .OrderBy(_ => random.Next()) .ToList(); // 为每个日期生成Usage实例,Count由AutoFixture自动填充 return uniqueDates.Select(date => fixture.Build<Usage>().With(u => u.DateTime, date).Create()) .ToList(); })); // 生成10个Report实例(可按需调整数量) var reports = fixture.CreateMany<Report>(10).ToList();
方案2:自定义ISpecimenBuilder(适合复杂对象图)
如果实际对象结构更复杂,推荐用ISpecimenBuilder封装定制逻辑,避免代码耦合,同时保留AutoFixture对其他属性的自动生成能力:
自定义Builder类
public class ReportUsageSpecimenBuilder : ISpecimenBuilder { private readonly Random _random = new Random(); public object Create(object request, ISpecimenContext context) { // 仅处理Report类的Usage属性 var propertyInfo = request as PropertyInfo; if (propertyInfo?.DeclaringType == typeof(Report) && propertyInfo.Name == nameof(Report.Usage)) { var usageCount = _random.Next(15, 31); var startDate = DateTime.Today.AddDays(-29); var uniqueDates = Enumerable.Range(0, usageCount) .Select(i => startDate.AddDays(i)) .OrderBy(_ => _random.Next()) .ToList(); // 通过AutoFixture生成Usage实例,仅替换DateTime属性 return uniqueDates.Select(date => { var usage = context.Resolve<Usage>() as Usage; usage.DateTime = date; return usage; }).ToList(); } // 非目标请求,返回NoSpecimen让AutoFixture默认处理 return new NoSpecimen(); } }
使用Builder
var fixture = new Fixture(); // 添加自定义Builder到Fixture的定制链中 fixture.Customizations.Add(new ReportUsageSpecimenBuilder()); // 生成多组Report实例 var reports = fixture.CreateMany<Report>(10).ToList();
关键细节说明
- 日期唯一性:通过生成连续日期再打乱的方式保证不重复,若需要包含时间部分,可调整
startDate为DateTime.Now.AddDays(-29),并确保每个时间点唯一 - 随机数可控:若需要测试稳定性,可给
Random指定固定种子(如new Random(42)) - 扩展性:方案2的Builder模式可轻松扩展,比如后续需要调整日期范围、Usage数量区间,只需修改Builder内部逻辑即可
内容的提问来源于stack exchange,提问作者Complexity
相关产品推荐
相关产品推荐

