c# - 将 DRY 应用于 Autofixture "Build"语句

标签 c# autofixture

假设我有这个具体类:

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 知道我可以使用以下方法获取自定义的匿名类:

var newAnon = fixture.Build<User>();

最佳答案

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

重构为值对象

如果您要求 EmailFullName属性应该有特别限制的值,它可能表示而不是 Primitive Obsession ,目标 API 将受益于显式定义 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/

相关文章:

c# - Entity Framework 中的映射?

c# - 训练 tesseract 后 tessdata 文件夹中应该包含哪些文件?

c# - AutoFixture,创建电子邮件地址列表

c# - C#中字典中的字典

c# - 无法在 CollectionViewGroup 中找到 ToggleButton

c# - 如何将用户控件属性绑定(bind)到可观察集合中包含的可观察对象的属性

c# - 如何使用 Moq 和 Autofixture 模拟 Entity Framework 6

c# - AutoFixture AutoMoq 不为某些属性创建模拟

具有派生类型的 AutoFixture

c# - 将 AutoFixture 与最小起订量一起使用?