Autofixture: 耇雑な制玄を持぀オブゞェクトを生成する

䜜成日 2018幎08月26日  Â·  8コメント  Â·  ゜ヌス: AutoFixture/AutoFixture

AutoFixtureに、コンストラクタヌで重芁な制玄を持぀オブゞェクトを生成させるための最良の方法を芋぀けようずしおいたす。 たずえば、intを取り、玠数のみを受け入れるPrimeNumberデヌタ構造を䜿甚するずしたす。

AutoFixtureでこの皮の構造のむンスタンスを生成するための最良のアプロヌチは䜕でしょうか ぀たり、私は明らかにカスタマむズを䜜成したすが、そこに䜕を入れたすか

  • ランダムなintを生成し、そのうちの1぀が玠数になるたでルヌプしたすかたたはもちろん玠数生成アルゎリズムを実行したすか これはこの皮の制玄には受け入れられる可胜性がありたすが、制玄を遵守するのがより難しい堎合、それはすぐにコストがかかるこずになりたす。
  • いく぀かの蚱容可胜な倀の有限リストを提䟛したすか

さらに、理論的には個別にランダムにするこずができるいく぀かの匕数を取るもののむンスタンスを䜜成しようずしおいるずしたしょうが、それはそれらの間でいく぀かの怜蚌を行いたすたずえば、argAはargBの堎合にのみこの倀の範囲に入るこずができたすはtrueであり、argCはargA倀に応じお異なる怜蚌ルヌルに準拠する必芁がありたす。そうでない堎合、argC.XプロパティはargA.Xプロパティず䞀臎する必芁がありたす。

この堎合、あなたはどうしたすか

  • 倖郚怜蚌を気にせずに各タむプの有効なむンスタンスを䜜成するための1぀のカスタマむズず、有効なむンスタンスが䜜成されるたでルヌプしお、倧きな耇雑なオブゞェクトを䜜成しようずする別のカスタマむズ
  • 繰り返しになりたすが、有限の蚱容倀のリストを提䟛したす。これは、可胜性の振幅を倧幅に制限する可胜性がありたす。
  • 耇雑なオブゞェクトの怜蚌に適合する匕数のむンスタンスのみを䜜成する特別なカスタマむズを提䟛したす

そしお最埌に私はいく぀かの問題を䜜成するこずができたしたが、それらの䞻題はすべお同じ問題の異なる偎面であるず感じたした、新しいクラスを远加するたびにこの皮のカスタマむズを䜜成しお適甚する必芁があり、それらのカスタマむズを垞に維持する必芁がありたす怜蚌ルヌルの倉曎は倧倉な䜜業のように思われたすが、これを軜枛するためにいく぀かの手法を適甚しおいたすか

どうもありがずうございたした。長い間申し蚳ありたせんでした。投皿が乱雑にならないように願っおいたす。

最も参考になるコメント

良い䞀日 最埌に、私は答えるために少しタむプを割り圓おたした-非垞に遅れた返信をお詫びしたす😊

たず、AutoFixtureのコアは非垞に単玔であり、制玄のある耇雑なツリヌのサポヌトが組み蟌たれおいないこずに泚意しおください。 芁するに、䜜成戊略は次のようなものです。

  • パブリックコンストラクタヌたたは静的ファクトリメ゜ッド珟圚のタむプのむンスタンスを返す静的メ゜ッドを探したす。
  • コンストラクタヌ匕数を解決し、むンスタンスをアクティブ化したす。
  • 曞き蟌み可胜なパブリックプロパティずフィヌルドに生成された倀を入力したす。

珟圚のアプロヌチでは、以前に発芋したように、どういうわけか䟝存関係の制玄を制埡するこずはできたせん。

特定のタむプを構築する方法を指定するためのカスタマむズポむントがいく぀かありたすが、それらは比范的単玔であり、それらの耇雑なルヌルをサポヌトしおいたせん。

AutoFixtureでこの皮の構造のむンスタンスを生成するための最良のアプロヌチは䜕でしょうか ぀たり、私は明らかにカスタマむズを䜜成したすが、そこに䜕を入れたすか

  • ランダムなintを生成し、そのうちの1぀が玠数になるたでルヌプしたすかたたはもちろん玠数生成アルゎリズムを実行したすか これはこの皮の制玄には受け入れられる可胜性がありたすが、制玄を遵守するのがより難しい堎合、それはすぐにコストがかかるこずになりたす。

  • いく぀かの蚱容可胜な倀の有限リストを提䟛したすか

残念ながら、ここには特効薬はありたせん。アプロヌチは状況によっお異なりたす。 倀がランダムすぎるこずに䟝存しない堎合、たたは単䞀のSUTが1〜2の玠数しか消費しない堎合は、玠数をハヌドコヌディングしおそれらから遞択するのが適切な堎合がありたす ElementsBulider<>組み蟌みヘルパヌがありたすそのような堎合。 䞀方、玠数の倧芏暡なリストが必芁で、長い玠数シヌケンスを操䜜する堎合は、それらを動的に生成するアルゎリズムをコヌディングするこずをお勧めしたす。

さらに、理論的には個別にランダムにするこずができるいく぀かの匕数を取るもののむンスタンスを䜜成しようずしおいるずしたしょうが、それはそれらの間でいく぀かの怜蚌を行いたすたずえば、argAはargBの堎合にのみこの倀の範囲に入るこずができたすはtrueであり、argCはargA倀に応じお異なる怜蚌ルヌルに準拠する必芁がありたす。そうでない堎合、argC.XプロパティはargA.Xプロパティず䞀臎する必芁がありたす。

この堎合、あなたはどうしたすか

本圓に良い質問ですが、残念ながらAutoFixtureでは箱から出しおすぐにそれをうたく解決するこずはできたせん。 通垞、私はタむプごずにカスタマむズを分離しようずしおいるので、1぀のタむプのカスタマむズは、単䞀のタむプの䜜成のみを制埡したす。 しかし、私の堎合、タむプは独立しおおり、明らかにあなたのケヌスではうたく機胜したせん。 たた、AutoFixtureはすぐに䜿甚できるコンテキストを提䟛しないため、特定のタむプのカスタマむズを䜜成する堎合、でオブゞェクト内郚的には暙本ず呌ばれるを䜜成しおいるコンテキストを明確に理解するこずはできたせん。

私の頭の䞊に、私は通垞、次の戊略をお勧めするず思いたす

  • 単䞀のオブゞェクトタむプのみの䜜成を制埡する方法で、タむプごずにカスタマむズを䜜成しおみおください。
  • 特定の制玄を䜿甚しお䟝存関係を䜜成する必芁がある堎合は、カスタマむズでもそれらの䟝存関係を有効化するこずをお勧めしたす。 䟝存関係が倉曎可胜である堎合は、AutoFixtureに䟝存関係を䜜成しおもらい、埌で互換性があるように構成するこずができたす。

このようにしお、内郚アヌキテクチャずあたり矛盟しないようにし、それがどのように機胜するかが明確になりたす。 もちろん、この方法は非垞に冗長になる可胜性がありたす。

耇雑な制玄のあるケヌスがそれほど䞀般的でない堎合は、既存の機胜で十分な堎合がありたす。 しかし、ドメむンモデルがそのようなケヌスで本圓にいっぱいである堎合、率盎に蚀っおAutoFixtureはあなたにずっお最良のツヌルではないかもしれたせん。 おそらく、このような問題を最も゚レガントな方法で解決できる、より優れたツヌルが垂堎に出回っおいたす。 もちろん、AutoFixtureは非垞に柔軟性があり、ほずんどすべおをオヌバヌラむドできるため、AutoFixtureコアの䞊にい぀でも独自のDSLを䜜成できたす...ただし、どちらの方法が安䟡かを評䟡する必芁がありたす😉

@ploehにも圌の考えを聞いおみたしょう。 通垞、マヌクの答えは深く、結果を解決するのではなく、最初に根本的な原因を芋぀けようずしたす😅

他にご䞍明な点がございたしたら、お問い合わせください。 い぀でもお答えいたしたす。

PS FWIW、私はあなたにサンプルを提䟛するこずに決めたした、そこで私はAutoFixtureで遊んで、同様の問題を解決しようずしたした私はそれを単玔に保ずうずしたした、そしおあなたの堎合それは完党に機胜しないかもしれたせん


クリックしお゜ヌスコヌドを衚瀺

`` `c
システムを䜿甚する;
AutoFixtureを䜿甚したす。
AutoFixture.Xunit2を䜿甚したす。
Xunitを䜿甚する;

名前空間AutoFixturePlayground
{{
パブリック静的クラスUtil
{{
public static bool IsPrimeint number
{{
//からコピヌhttps://stackoverflow.com/a/15743238/2009373

        if (number <= 1) return false;
        if (number == 2) return true;
        if (number % 2 == 0) return false;

        var boundary = (int) Math.Floor(Math.Sqrt(number));

        for (int i = 3; i <= boundary; i += 2)
        {
            if (number % i == 0) return false;
        }

        return true;
    }
}

public class DepA
{
    public int Value { get; set; }
}

public class DepB
{
    public int PrimeNumber { get; }
    public int AnyOtherValue { get; }

    public DepB(int primeNumber, int anyOtherValue)
    {
        if (!Util.IsPrime(primeNumber))
            throw new ArgumentOutOfRangeException(nameof(primeNumber), primeNumber, "Number is not prime.");

        PrimeNumber = primeNumber;
        AnyOtherValue = anyOtherValue;
    }
}

public class DepC
{
    public DepA DepA { get; }
    public DepB DepB { get; }

    public DepC(DepA depA, DepB depB)
    {
        if (depB.PrimeNumber < depA.Value)
            throw new ArgumentException("Second should be larger than first.");

        DepA = depA;
        DepB = depB;
    }

    public int GetPrimeNumber() => DepB.PrimeNumber;
}

public class Issue1067
{
    [Theory, CustomAutoData]
    public void ShouldReturnPrimeNumberFromDepB(DepC sut)
    {
        var result = sut.GetPrimeNumber();

        Assert.Equal(sut.DepB.PrimeNumber, result);
    }
}

public class CustomAutoData : AutoDataAttribute
{
    public CustomAutoData() : base(() =>
    {
        var fixture = new Fixture();

        // Add prime numbers generator, returning numbers from the predefined list
        fixture.Customizations.Add(new ElementsBuilder<PrimeNumber>(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41));

        // Customize DepB to pass prime numbers only to ctor
        fixture.Customize<DepB>(c => c.FromFactory((PrimeNumber pn, int anyNumber) => new DepB(pn, anyNumber)));

        // Customize DepC, so that depA.Value is always less than depB.PrimeNumber
        fixture.Customize<DepC>(c => c.FromFactory((DepA depA, DepB depB, byte diff) =>
        {
            depA.Value = depB.PrimeNumber - diff;
            return new DepC(depA, depB);
        }));

        return fixture;
    })
    {
    }
}

/// <summary>
/// A helper type to represent a prime number, so that you can resolve prime numbers 
/// </summary>
public readonly struct PrimeNumber
{
    public int Value { get; }

    public PrimeNumber(int value)
    {
        Value = value;
    }

    public static implicit operator int(PrimeNumber prime) => prime.Value;
    public static implicit operator PrimeNumber(int value) => new PrimeNumber(value);
}

}
`` `

党おのコメント8件

無線封止でごめんなさい。 私たちは生きおいたす、そしお私はすぐに返事をしたす-最近私の䞻芁な仕事で非垞に忙しいです。 NSubstitute v4リリヌスにも取り組んでいるため、時間は非垞に限られおいたす。リ゜ヌス物思いにふける質問は難しいので、回答を投皿する前に、考えられるすべおの方法に぀いお考えおください。

忍耐をありがずう、お楜しみにりィンク

やあ、
そのニュヌスはありたすか
プレッシャヌはありたせん私はドリルを知っおいたす😄、そしおそれは実際にはブロックされおいたせん、私はいく぀かの知識に基づいたアドバむスが本圓に欲しいです、それはあなたがある皋床の可芖性を持っおいるかどうかを知るこずだけです。
どうもありがずう

良い䞀日 最埌に、私は答えるために少しタむプを割り圓おたした-非垞に遅れた返信をお詫びしたす😊

たず、AutoFixtureのコアは非垞に単玔であり、制玄のある耇雑なツリヌのサポヌトが組み蟌たれおいないこずに泚意しおください。 芁するに、䜜成戊略は次のようなものです。

  • パブリックコンストラクタヌたたは静的ファクトリメ゜ッド珟圚のタむプのむンスタンスを返す静的メ゜ッドを探したす。
  • コンストラクタヌ匕数を解決し、むンスタンスをアクティブ化したす。
  • 曞き蟌み可胜なパブリックプロパティずフィヌルドに生成された倀を入力したす。

珟圚のアプロヌチでは、以前に発芋したように、どういうわけか䟝存関係の制玄を制埡するこずはできたせん。

特定のタむプを構築する方法を指定するためのカスタマむズポむントがいく぀かありたすが、それらは比范的単玔であり、それらの耇雑なルヌルをサポヌトしおいたせん。

AutoFixtureでこの皮の構造のむンスタンスを生成するための最良のアプロヌチは䜕でしょうか ぀たり、私は明らかにカスタマむズを䜜成したすが、そこに䜕を入れたすか

  • ランダムなintを生成し、そのうちの1぀が玠数になるたでルヌプしたすかたたはもちろん玠数生成アルゎリズムを実行したすか これはこの皮の制玄には受け入れられる可胜性がありたすが、制玄を遵守するのがより難しい堎合、それはすぐにコストがかかるこずになりたす。

  • いく぀かの蚱容可胜な倀の有限リストを提䟛したすか

残念ながら、ここには特効薬はありたせん。アプロヌチは状況によっお異なりたす。 倀がランダムすぎるこずに䟝存しない堎合、たたは単䞀のSUTが1〜2の玠数しか消費しない堎合は、玠数をハヌドコヌディングしおそれらから遞択するのが適切な堎合がありたす ElementsBulider<>組み蟌みヘルパヌがありたすそのような堎合。 䞀方、玠数の倧芏暡なリストが必芁で、長い玠数シヌケンスを操䜜する堎合は、それらを動的に生成するアルゎリズムをコヌディングするこずをお勧めしたす。

さらに、理論的には個別にランダムにするこずができるいく぀かの匕数を取るもののむンスタンスを䜜成しようずしおいるずしたしょうが、それはそれらの間でいく぀かの怜蚌を行いたすたずえば、argAはargBの堎合にのみこの倀の範囲に入るこずができたすはtrueであり、argCはargA倀に応じお異なる怜蚌ルヌルに準拠する必芁がありたす。そうでない堎合、argC.XプロパティはargA.Xプロパティず䞀臎する必芁がありたす。

この堎合、あなたはどうしたすか

本圓に良い質問ですが、残念ながらAutoFixtureでは箱から出しおすぐにそれをうたく解決するこずはできたせん。 通垞、私はタむプごずにカスタマむズを分離しようずしおいるので、1぀のタむプのカスタマむズは、単䞀のタむプの䜜成のみを制埡したす。 しかし、私の堎合、タむプは独立しおおり、明らかにあなたのケヌスではうたく機胜したせん。 たた、AutoFixtureはすぐに䜿甚できるコンテキストを提䟛しないため、特定のタむプのカスタマむズを䜜成する堎合、でオブゞェクト内郚的には暙本ず呌ばれるを䜜成しおいるコンテキストを明確に理解するこずはできたせん。

私の頭の䞊に、私は通垞、次の戊略をお勧めするず思いたす

  • 単䞀のオブゞェクトタむプのみの䜜成を制埡する方法で、タむプごずにカスタマむズを䜜成しおみおください。
  • 特定の制玄を䜿甚しお䟝存関係を䜜成する必芁がある堎合は、カスタマむズでもそれらの䟝存関係を有効化するこずをお勧めしたす。 䟝存関係が倉曎可胜である堎合は、AutoFixtureに䟝存関係を䜜成しおもらい、埌で互換性があるように構成するこずができたす。

このようにしお、内郚アヌキテクチャずあたり矛盟しないようにし、それがどのように機胜するかが明確になりたす。 もちろん、この方法は非垞に冗長になる可胜性がありたす。

耇雑な制玄のあるケヌスがそれほど䞀般的でない堎合は、既存の機胜で十分な堎合がありたす。 しかし、ドメむンモデルがそのようなケヌスで本圓にいっぱいである堎合、率盎に蚀っおAutoFixtureはあなたにずっお最良のツヌルではないかもしれたせん。 おそらく、このような問題を最も゚レガントな方法で解決できる、より優れたツヌルが垂堎に出回っおいたす。 もちろん、AutoFixtureは非垞に柔軟性があり、ほずんどすべおをオヌバヌラむドできるため、AutoFixtureコアの䞊にい぀でも独自のDSLを䜜成できたす...ただし、どちらの方法が安䟡かを評䟡する必芁がありたす😉

@ploehにも圌の考えを聞いおみたしょう。 通垞、マヌクの答えは深く、結果を解決するのではなく、最初に根本的な原因を芋぀けようずしたす😅

他にご䞍明な点がございたしたら、お問い合わせください。 い぀でもお答えいたしたす。

PS FWIW、私はあなたにサンプルを提䟛するこずに決めたした、そこで私はAutoFixtureで遊んで、同様の問題を解決しようずしたした私はそれを単玔に保ずうずしたした、そしおあなたの堎合それは完党に機胜しないかもしれたせん


クリックしお゜ヌスコヌドを衚瀺

`` `c
システムを䜿甚する;
AutoFixtureを䜿甚したす。
AutoFixture.Xunit2を䜿甚したす。
Xunitを䜿甚する;

名前空間AutoFixturePlayground
{{
パブリック静的クラスUtil
{{
public static bool IsPrimeint number
{{
//からコピヌhttps://stackoverflow.com/a/15743238/2009373

        if (number <= 1) return false;
        if (number == 2) return true;
        if (number % 2 == 0) return false;

        var boundary = (int) Math.Floor(Math.Sqrt(number));

        for (int i = 3; i <= boundary; i += 2)
        {
            if (number % i == 0) return false;
        }

        return true;
    }
}

public class DepA
{
    public int Value { get; set; }
}

public class DepB
{
    public int PrimeNumber { get; }
    public int AnyOtherValue { get; }

    public DepB(int primeNumber, int anyOtherValue)
    {
        if (!Util.IsPrime(primeNumber))
            throw new ArgumentOutOfRangeException(nameof(primeNumber), primeNumber, "Number is not prime.");

        PrimeNumber = primeNumber;
        AnyOtherValue = anyOtherValue;
    }
}

public class DepC
{
    public DepA DepA { get; }
    public DepB DepB { get; }

    public DepC(DepA depA, DepB depB)
    {
        if (depB.PrimeNumber < depA.Value)
            throw new ArgumentException("Second should be larger than first.");

        DepA = depA;
        DepB = depB;
    }

    public int GetPrimeNumber() => DepB.PrimeNumber;
}

public class Issue1067
{
    [Theory, CustomAutoData]
    public void ShouldReturnPrimeNumberFromDepB(DepC sut)
    {
        var result = sut.GetPrimeNumber();

        Assert.Equal(sut.DepB.PrimeNumber, result);
    }
}

public class CustomAutoData : AutoDataAttribute
{
    public CustomAutoData() : base(() =>
    {
        var fixture = new Fixture();

        // Add prime numbers generator, returning numbers from the predefined list
        fixture.Customizations.Add(new ElementsBuilder<PrimeNumber>(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41));

        // Customize DepB to pass prime numbers only to ctor
        fixture.Customize<DepB>(c => c.FromFactory((PrimeNumber pn, int anyNumber) => new DepB(pn, anyNumber)));

        // Customize DepC, so that depA.Value is always less than depB.PrimeNumber
        fixture.Customize<DepC>(c => c.FromFactory((DepA depA, DepB depB, byte diff) =>
        {
            depA.Value = depB.PrimeNumber - diff;
            return new DepC(depA, depB);
        }));

        return fixture;
    })
    {
    }
}

/// <summary>
/// A helper type to represent a prime number, so that you can resolve prime numbers 
/// </summary>
public readonly struct PrimeNumber
{
    public int Value { get; }

    public PrimeNumber(int value)
    {
        Value = value;
    }

    public static implicit operator int(PrimeNumber prime) => prime.Value;
    public static implicit operator PrimeNumber(int value) => new PrimeNumber(value);
}

}
`` `

こんにちは@zvirja

うわヌ、詳现な答えをありがずう、それは本圓に面癜いです。 私はいく぀かのテストを行い、それが䜕をする䟡倀があるかを芋積もる必芁がありたすが、党䜓ずしおこれは玠晎らしいこずです。

凊理する䟝存関係がそれほど倚くないず思うので、あなたのアプロヌチが良い方法かもしれたせん。 もちろん、 @ ploehに远加するものがあれば、光栄に思いたす👌

もう䞀床ありがずう、良い仕事を続けおください

AutoFixtureずプロパティベヌスのテストの䞡方での私の経隓では、次のような問題に察凊するには、基本的に2぀の方法がありたす。

  • フィルタリング
  • アルゎリズムによる䜜成

私が曞いおいるように、私の盎感は、これらがそれぞれ_catamorphisms_ず_anamorphisms_である可胜性があるこずを瀺唆しおいたすが、これに぀いおもう少し考える必芁があるので、これはさおおき、ほずんど私自身ぞのメモです。

ランダムに生成された倀のほずんどが、適合しなければならない制玄に適合する堎合は、既存のゞェネレヌタヌを䜿甚したすが、時折䞍適切な倀を砎棄するこずが、問題に察凊する最も簡単な方法である可胜性がありたす。

䞀方、フィルタヌがほずんどのランダムデヌタを砎棄するこずを意味する堎合は、代わりに、おそらくランダムシヌド倀に基づいお、問題の制玄に適合する倀を生成するアルゎリズムを考え出す必芁がありたす。

数幎前、私はFsCheckのコンテキストで䞡方のアプロヌチのいく぀かの簡単な䟋を瀺す講挔をしたした。 このプレれンテヌションは、実際には同じアプロヌチを採甚したトヌクの進化圢ですが、代わりにAutoFixtureを䜿甚しおいたす。 残念ながら、その話の録音はありたせん。

䞡方の方法で玠数の芁件に察凊できたす。

フィルタのアプロヌチは、制玄のない数を生成し、実際に玠数になるたで数を砎棄するこずです。

アルゎリズムのアプロヌチは、玠数を生成するために玠数ふるいのようなアルゎリズムを䜿甚するこずです。 ただし、これはランダムではないため、ランダム化する方法を理解するこずをお勧めしたす。

AutoFixtureで制玄された倀を凊理する方法に関する党䜓的な質問は、他の人がラむブラリを芋始めるずすぐに出おきたした。圓時、私はただ参照しおいる蚘事を曞きたした http 

盞互に関連する耇数の倀の質問に関しお、私は䞀般的なガむダンスを䞎えたくありたせん。 この皮の質問は、倚くの堎合XY問題です。 倚くの堎合、詳现を理解すれば、代替蚭蚈によっおAutoFixtureだけでなく、補品コヌドベヌス自䜓の問題も解決できる可胜性がありたす。

XY問題が存圚する堎合でも、これが正圓な懞念事項ずなる可胜性がある状況はただありたすが、私の経隓では、それらはケヌスバむケヌスで察凊したいず思いたす。レア。

ですから、具䜓的な䟋があればお圹に立おればず思いたすが、䞀般的な質問に有意矩に答えられるずは思いたせん。

@ploehこの回答に感謝したす。これは、私が怜蚎しおいたアプロヌチを裏付けるものですそしお、カタモルフィズムずアナモルフィズムに興味を持っおくれたした😃。
私は盞互䟝存倀がほずんどXY問題であるこずに完党に同意したす少なくずも私の堎合、問題は、レガシヌテストされおいない😢コヌドで䜜業するずき、それらの倀を扱うこずは、私たちが埗るたで、ずにかくいく぀かのテストを曞くための良いスタヌトだったずいうこずですこれを適切にリファクタリングする時間。

ずにかく、あなたの答えは䞡方ずも問題に非垞にうたく察凊しおいたす、私はそこから行くのは良いこずだず思いたす。
ありがずう

ずころで、私は@zvirjaぞの远加ずしお私の答えを意味するだけだず蚀うのを忘れたした。 それはすでにそこに良い答えです👍

私はそれを他の方法でずらなかった😄

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡