web-dev-qa-db-ja.com

AutoFixtureを使用して、タイプのカスタマイズを維持しながら、カスタマイズされたプロパティでビルドする方法は?

Autofixtureを使用してオブジェクトを作成しようとしていますが、常にデフォルトにしたい特定のプロパティがあります(残りは自動生成できます)。ただし、カスタマイズをセットアップすると、カスタマイズでビルドすると上書きされます。

void Main()
{
    var fixture = new Fixture();
    fixture.Customize<Person>(composer => composer.With(p => p.Name, "Ben"));

    var person = fixture.Build<Person>()
        .With(p => p.DateOfBirth, new DateTime(1900, 1, 1))
        .Create();

    /*  RESULT OF person below
    Name    null
    DateOfBirth 1/1/1900
    StreetAddress   StreetAddressafd6b86b-376a-4355-9a9c-fbae34731453
    State   State019e867b-ac5e-418f-805b-a64146bc06bc
    */
}

public class Person
{
    public string Name { get; set;}

    public DateTime DateOfBirth { get; set;}

    public string StreetAddress { get; set;}

    public string State { get; set;}
}

NameプロパティとDateOfBirthプロパティのカスタマイズは競合しないため、名前が最終的にnullになる理由はわかりません。名前はBenになると思います。

両方のカスタマイズが適用されるようにするにはどうすればよいですか(つまり、Name = "Ben"およびDateOfBirth = 1/1/1900)?

15
Ben Anderson

@DavidOsborneが正しく指摘したように、表示される動作は 設計どおり です。

より良いアプローチ は、カスタマイズを個別のクラスに編成し、特定のテストシナリオで必要に応じてそれらを有効にすることです。

カスタマイゼーションオブジェクトはICustomizationインターフェイスを実装し、その仕事はFixtureオブジェクトを特定の方法で構成することです。次に例を示します。

public class AllPersonsAreNamedBen : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Person>(composer =>
            composer.With(p => p.Name, "Ben"));
    }
}

public class AllPersonsAreBornIn1900 : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Person>(composer =>
            composer.With(p => p.DateOfBirth, new DateTime(1900, 1, 1)));
    }
}

Fixtureメソッドを使用して、特定のCustomizeのカスタマイズを有効にすることができます。次に例を示します。

fixture.Customize(new AllPersonsAreNamedBen());

または:

fixture.Customize(new AllPersonsAreBornIn1900());

CompositeCustomizationクラスを使用して、複数のカスタマイズを新しいものに結合することもできます。

public class AllPersonsAreNamedBenAndAreBornIn1900 : CompositeCustomization
{
    public AllPersonsAreNamedBenAndAreBornIn1900()
        : base(new AllPersonsAreNamedBen(),
               new AllPersonsAreBornIn1900())
    {
    }
}

その時点で簡単に言うことができます:

fixture.Customize(new AllPersonsAreNamedBenAndAreBornIn1900());

ただし、カスタマイズがFixtureに適用される順序が重要であることに注意してください。最後のものが勝ち、潜在的にoverride @MarkSeemannがコメントで指摘したように、以前のもの。これも 仕様による です。

したがって、can異なるタイプで機能する既存のカスタマイズを組み合わせる一方で、この特定のケースでは、両方のカスタマイズが同じタイプを対象としているため、Personタイプのすべての設定を組み合わせてカプセル化するには、新しいカスタマイズを作成する必要があります。

public class AllPersonsAreNamedBenAndAreBornIn1900 : CompositeCustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Person>(composer =>
            composer.With(p => p.Name, "Ben")
                    .With(p => p.DateOfBirth, new DateTime(1900, 1, 1)));
    }
}

一般的な規則として、カスタマイズを小さくし、focusedを使用すると、さまざまなテストで 再利用 を実行して、特定のテストにそれらを組み合わせることができますシナリオ。

15

これは仕様によるものです。

Buildメソッドチェーンは、1回限りのカスタマイズとして最もよく理解されることに注意してください。 Fixtureインスタンスのすべてのカスタマイズをバイパスします。代わりに、特定の標本を構築するときにきめ細かな制御が可能になります。ただし、ほとんどの場合、規約ベースのICustomizationを追加する方が、より優れた、より柔軟なオプションです。

...Build()メソッドのドキュメントから。

これはおそらく理想的な答えではありません。ただし、ドキュメントには、どのように到達するかに関するヒントが記載されています。

10
David Osborne