6

AutoFixtureの作成時の動作をカスタマイズして、フィクスチャのプロパティが生成および割り当てられた後にいくつかの依存オブジェクトを設定できるようにしたいと考えています。

たとえば、特定のテストセットではプロパティが常にfalseである必要があるUserため、をカスタマイズするメソッドがあるとします。IsDeleted

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

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

このようなことは可能ですか?または、匿名オブジェクトグラフを作成するという私の目標を達成するためのより良い方法がありますか?

4

2 に答える 2

6

このBuild方法の場合、これは不可能であり、おそらくこれは不可能です。これは、はるかに優れたオプションが利用できるためです。

まず第一に、メソッドの周りに静的ヘルパーメソッドを記述する必要はありませんBuild。このBuild方法は、事実の前にプロパティまたはフィールドの値を定義する必要がある、真に1回限りの初期化用です。

つまり、次のようなクラスを想像してください。

public class MyClass
{
    private string txt;

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

この(考案された)例ではfixture.CreateAnonymous<MyClass>、プロパティに「バー」以外のものを割り当てようとしているため、ストレートがスローされます。

1回限りのシナリオでは、Buildこの方法を使用してこの問題を回避できます。1つの例は、値を明示的に「bar」に設定することです。

var mc =
    fixture.Build<MyClass>().With(x => x.SomeWeirdText, "bar").CreateAnonymous();

ただし、さらに簡単なのは、そのプロパティを省略することです。

var mc =
    fixture.Build<MyClass>().Without(x => x.SomeWeirdText).CreateAnonymous();

ただし、これを繰り返し実行したい場合は、より適切なオプションがあります。AutoFixtureには、物事の作成方法を定義するための非常に洗練されたカスタマイズ可能なエンジンがあります。

まず、次のように、プロパティの省略をカスタマイズに移動することから始めることができます。

fixture.Customize<MyClass>(c => c.Without(x => x.SomeWeirdText));

これで、フィクスチャがMyClassのインスタンスを作成するたびに、そのプロパティを完全にスキップします。後で値を割り当てることもできます。

var mc = fixture.CreateAnonymous<MyClass>();
my.SomeWeirdText = "bar";

より洗練されたものが必要な場合は、カスタムISpecimenBuilderを実装できます。インスタンスの作成後にカスタムコードを実行する場合は、独自のISpecimenBuilderをポストプロセッサで装飾し、デリゲートを指定できます。これは次のようになります。

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

(ところで、あなたはまだAutoFixture 1.0を使用していますか?IIRC、ObjectBuilder<T>それ以来、周りはありませんでした...)

于 2012-04-12T19:44:28.853 に答える
3

AutoFixture CodePlexサイトで、このトピックに関する有益な議論があります。

そこにリンクされているポストプロセッサのカスタマイズが役立つと思います。使用例:

class AutoControllerDataAttribute : AutoDataAttribute
{  
    public AutoControllerDataAttribute()
        : this( new Fixture() )
    {
    }

    public AutoControllerDataAttribute( IFixture fixture )
        : base( fixture )
    {
        fixture.Customize( new AutoMoqCustomization() );
        fixture.Customize( new ApplyControllerContextCustomization() );
    }

    class ApplyControllerContextCustomization : PostProcessWhereIsACustomization<Controller>
    {
        public ApplyControllerContextCustomization()
            : base( PostProcess )
        {
        }

        static void PostProcess( Controller controller )
        {
            controller.FakeControllerContext();
            // etc. - add stuff you want to happen after the instance has been created
于 2012-07-25T20:14:03.667 に答える