AutoFixture可以在对象创建时执行委托吗?

lad*_*dge 6 c# autofixture

我想定制AutoFixture的创建时行为,这样我可以在生成和分配灯具的属性后设置一些相关对象.

例如,假设我有一个自定义a的方法,User因为IsDeleted对于某组测试,它的属性总是必须为false:

public class User
{
   public int Id { get; set; }
   public string Name { get; set; }
   public bool IsDeleted { get; set; }
}

public static ObjectBuilder<User> BuildUser(this Fixture f)
{
   return f.Build<User>().With(u => u.IsDeleted, false);
}
Run Code Online (Sandbox Code Playgroud)

(我交回ObjectBuilder测试,以便在必要时可以进一步定制夹具.)

我想做的是Id在创建时自动将该用户与匿名集合相关联,但我不能这样做,因为Id当我将返回值返回到单元测试时尚未生成正确.这是我正在尝试做的事情:

public static ObjectBuilder<User> BuildUserIn(this Fixture f, UserCollection uc)
{
   return f.Build<User>()
           .With(u => u.IsDeleted, false);
           .AfterCreation(u =>
            {
               var relation = f.Build<UserCollectionMembership>()
                               .With(ucm => ucm.UserCollectionId, uc.Id)
                               .With(ucm => ucm.UserId, u.Id)
                               .CreateAnonymous();
               Repository.Install(relation);
            }
}
Run Code Online (Sandbox Code Playgroud)

这样的事情可能吗?或者也许有更好的方法来实现我创建匿名对象图的目标?

Mar*_*ann 6

对于该Build方法,这是不可能的,也可能永远不会,因为有更好的选择.

首先,永远不必在该方法周围编写静态辅助方法Build.该Build方法用于真正的一次性初始化,其中需要在事实之前定义属性或字段值.

即想象一个这样的类:

public class MyClass
{
    private string txt;

    public string SomeWeirdText
    {
        get { return this.txt; }
        set
        {
            if (value != "bar")
                throw new ArgumentException();
            this.txt = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这一(人为)例如,直fixture.CreateAnonymous<MyClass>是要扔掉,因为它会尝试给比"巴"的财产以外的东西.

在一次性场景中,可以使用该Build方法来解决此问题.一个例子就是将值明确设置为"bar":

var mc =
    fixture.Build<MyClass>().With(x => x.SomeWeirdText, "bar").CreateAnonymous();
Run Code Online (Sandbox Code Playgroud)

但是,更简单的是省略该属性:

var mc =
    fixture.Build<MyClass>().Without(x => x.SomeWeirdText).CreateAnonymous();
Run Code Online (Sandbox Code Playgroud)

但是,一旦你开始想要反复这样做,有更好的选择.AutoFixture有一个非常复杂和可定制的引擎,用于定义创建事物的方式.

首先,可以将遗漏属性转换为自定义,如下所示:

fixture.Customize<MyClass>(c => c.Without(x => x.SomeWeirdText));
Run Code Online (Sandbox Code Playgroud)

现在,每当fixture创建一个MyClass实例时,它就会完全跳过该属性.您仍然可以在之后分配值:

var mc = fixture.CreateAnonymous<MyClass>();
my.SomeWeirdText = "bar";
Run Code Online (Sandbox Code Playgroud)

如果您想要更复杂的东西,可以实现自定义的ISpecimenBuilder.如果要在创建实例后运行一些自定义代码,可以使用后处理器装饰自己的ISpecimenBuilder并提供委托.这可能看起来像这样:

fixture.Customizations.Add(
    new Postprocessor(yourCustomSpecimenBuilder, obj =>
        { */ do something to obj here */ }));
Run Code Online (Sandbox Code Playgroud)

(顺便说一句,你还在使用AutoFixture 1.0吗?IIRC,ObjectBuilder<T>从那时起就没有了...)