假设我有这个具体的类(class):

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

我想创建一个具有有效电子邮件地址的匿名实例,并且全名字段不得超过20个字符。我可以做这个:
var fixture = new Fixture();
var anonUser = fixture.Build<User>()
    .With(x => x.Email, string.Format("{0}@fobar.com", fixture.Create<string>()))
    .With(x => x.FullName,  fixture.Create<string>()Substring(0,20))
    .Create();

有没有一种方法可以在一个地方定义它,以便AF知道我可以使用以下方法获取自定义的anon类:
var newAnon = fixture.Build<User>();

最佳答案

您有多种选择。我认为,最好的选择是将GOOS原理应用于您的测试。当测试变得难以编写时,该重新考虑被测系统(SUT)的设计了。 AutoFixture倾向于放大此效果。

重构为值对象

如果您要求EmailFullName属性应具有特别受约束的值,则它可能指示目标API而不是Primitive Obsession将从定义显式EmailFullName 值对象中受益。 canonical AutoFixture example is about phone numbers

使用数据注释

您还可以使用data annotations给出有关值约束的AutoFixture提示。并非所有数据注释属性都受支持,但是您可以同时使用MaxLengthRegularExpression

它可能看起来像这样:

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; }
}

我个人不喜欢这种方法,因为我更喜欢proper encapsulation

使用自定义

不要使用Build<T>方法,而要使用Customize<T>方法:
var fixture = new Fixture();
fixture.Customize<User>(c => c
    .With(x => x.Email, string.Format("{0}@fobar.com", fixture.Create<string>())
    .With(x => x.FullName, fixture.Create<string>().Substring(0,20)));
var newAnon = fixture.Create<User>();

编写一个由惯例驱动的标本生成器

最后,您可以编写一个convention-driven customization:
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)));
    }
}

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

关于c# - 将DRY应用于Autofixture "Build"语句,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22331791/

10-11 15:25