将DRY应用于自动混合“构建”语句

假设我有这个具体的类:

public partial class User { public int ID { get; set; } public string Email { get; set; } public string FullName { get; set; } } 

我想创建一个具有有效电子邮件地址的匿名实例,并且fullname字段不超过20个字符。 我可以做这个:

 var fixture = new Fixture(); var anonUser = fixture.Build() .With(x => x.Email, string.Format("{0}@fobar.com", fixture.Create())) .With(x => x.FullName, fixture.Create()Substring(0,20)) .Create(); 

有没有办法可以在一个地方定义它,以便AF知道我可以通过使用以下方式获得我的自定义anon类:

 var newAnon = fixture.Build(); 

你有各种选择。 在我看来,最好的选择是应用GOOS原则来听你的测试 。 当测试变得难以编写时,是时候重新考虑被测系统(SUT)的设计了。 AutoFixture倾向于放大这种效果。

重构为值对象

如果您要求EmailFullName属性应具有特别受约束的值,则可能表示目标API将受益于定义显式EmailFullName 值对象 ,而不是Primitive Obsession 。 规范的AutoFixture示例是关于电话号码 。

使用数据注释

您还可以使用数据注释来提供有关值的约束的AutoFixture提示。 并非所有数据注释属性都受支持,但您可以同时使用MaxLength和RegularExpression 。

它可能看起来像这样:

 public partial class User { public int ID { get; set; } [RegularExpression("regex for emails is much harder than you think")] public string Email { get; set; } [MaxLenght(20)] public string FullName { get; set; } } 

就个人而言,我不喜欢这种方法,因为我更喜欢适当的封装 。

使用自定义

而不是使用Build方法,使用Customize方法:

 var fixture = new Fixture(); fixture.Customize(c => c .With(x => x.Email, string.Format("{0}@fobar.com", fixture.Create()) .With(x => x.FullName, fixture.Create().Substring(0,20))); var newAnon = fixture.Create(); 

编写一个约定驱动的Specimen Builder

最后,您可以编写一个约定驱动的自定义 :

 public class EmailSpecimenBuilder : ISpecimenBuilder { public object Create(object request, ISpecimenContext context) { var pi = request as PropertyInfo; if (pi == null) { return new NoSpecimen(request); } if (pi.PropertyType != typeof(string) || pi.Name != "Email") { return new NoSpecimen(request); } return string.Format("{0}@fobar.com", context.Resolve(typeof(string))); } } 

我非常喜欢这种方法,因为我可以在这里放置任意复杂的逻辑,因此我不需要创建大量的一次性自定义,而是可以使用一小组约定来驱动整个测试套件。 这也倾向于使目标代码更加一致。