0

純粋な関数を書くという考えは好きですが、それらを組み合わせてテスト可能なコードにする方法を理解するのに苦労しています。私はクラスを抽出してから適切にスタブ化することに慣れており、関数型プログラミングに関するいくつかの重要な洞察が欠けていると感じています。

これは、現在直面している問題からスリム化した例です。

日付のリストのリストを取得し、「機会」の基準を満たすものをフィルタリングしたいと考えています。

C# では次のようになります。

    static List<List<DateTime>> Opportunities(List<List<DateTime>> dates)
    {
        return dates.Where(ds => HasOpportunity(ds)).ToList();
    }

    static bool HasOpportunity(List<DateTime> dates)
    {
        var threshold = 0.05D;

        var current = OpportunityProbability(dates, DateTime.Now);
        var previous = OpportunityProbability(dates, DateTime.Now.Subtract(TimeSpan.FromDays(30)));

        return previous >= threshold && current < threshold;
    }

    static double OpportunityProbability(List<DateTime> dates, DateTime endDate)
    {
        // does lots of math
        return 0.0D;
    }

したがって、ヒントでは、OpportunityProbabilityテスト方法を知っています。私が抱えている問題はHasOpportunity、チェーン ( ) のさらに上にありOpportunitiesます。

テストする方法を知っている唯一の方法HasOpportunityは、スタブアウトするOpportunityProbabilityことですが、それはできません。OpportunityProbabilityまた、 をテストするために、 の設計を満たすために偽のデータを作成したくありませんHasOpportunity。したがって、両方の関数が純粋であるにもかかわらず、テスト可能ではなく、設計が悪いように感じます。

したがって、私は悪い機能コードを設計しているように感じます:)

私が気にしてHasOpportunityいるのは、主にブール値のテストです。2 つの double としきい値を指定すると、比較が行われ、結果が返されます。これらの 2 つの double を取得するために、日付のリストと日付を必要とする関数を使用します。これにより、日付 (および 30 日前)HasOpportunityの決定も担当することになります。DateTime.Now多分私はそれを分割することができます:

    static bool HasOpportunity(double probability1, double probability2)
    {
        var threshold = 0.05D;

        return probability2 >= threshold && probability1 < threshold;
    }

したがって、それは明らかにテスト可能です。しきい値を上に移動することもできます。

    static bool HasOpportunity(double threshold, double probability1, double probability2)
    {
        return probability2 >= threshold && probability1 < threshold;
    }

したがって、これはさらに一般的です。

これを行うときに遭遇する問題は、次のように移動したことOpportunitiesです。

    static List<List<DateTime>> Opportunities(List<List<DateTime>> dates)
    {
        return dates.Where(ds => {
            var current = OpportunityProbability(ds, DateTime.Now);
            var previous = OpportunityProbability(ds, DateTime.Now.Subtract(TimeSpan.FromDays(30)));
            return HasOpportunity(0.05D, current, previous);
        }).ToList();
    }

これは、次に取るべきステップがわからないところです。

機能的な大君主について何か考えはありますか?C# で F# を書くのを手伝ってください。よろしくお願いします!

アップデート

したがって、別の一歩を踏み出すと、次のようになります。

    static List<List<DateTime>> Opportunities(double threshold, DateTime currentDate, DateTime previousDate, List<List<DateTime>> dates)
    {
        return dates.Where(ds => {
            var current = OpportunityProbability(ds, currentDate);
            var previous = OpportunityProbability(ds, previousDate);
            return HasOpportunity(threshold, current, previous);
        }).ToList();
    }

したがって、これをテストする方法はまだわかりませんが、この関数のパラメーターが最終的に機会の定義を作成するという点で優れています。

  • しきい値
  • 初めてのデート
  • 二日目

そして、日付のリストのリストがあれば、機会を与えることができます。

4

2 に答える 2

2

高階関数の使用を検討しましたか? OpportunityProbability 関数を HasOpportunity に渡します。

static List<List<DateTime>> Opportunities(List<List<DateTime>> dates)
{
    return dates.Where(ds => HasOpportunity(ds, OpportunityProbability, OpportunityProbability)).ToList();
}

static bool HasOpportunity(List<DateTime> dates, Func<List<DateTime>, DateTime, double> currentProb, Func<List<DateTime>, DateTime, double> prevProb)
{
    var threshold = 0.05D;

    var current = currentProb(dates, DateTime.Now);
    var previous = prevProb(dates, DateTime.Now.Subtract(TimeSpan.FromDays(30)));

    return previous >= threshold && current < threshold;
}

static double OpportunityProbability(List<DateTime> dates, DateTime endDate)
{
    // does lots of math
    return 0.0D;
}

これで、OpportunityProbability と HasOpportunity の両方を互いに独立してテストできます (HasOpportunity の場合、2 番目と最後のパラメーターを「スタブ」します。さらに分離したい場合は、OpportunityProbability を Opportunities に渡すこともできます。

于 2013-06-16T17:36:10.513 に答える
0

古き良きオブジェクト指向を少し取り入れて、単一責任パターンを尊重する必要があると思います。考えられる方法の 1 つは、クラスを作成することです。

  • OpportunityCalculatorメソッドでdouble OpportunityProbability(List<DateTime> dates, DateTime endDate)

  • OpportunityFilterメソッドでbool HasOpportunity(double threshold, double probability1, double probability2)

これらのクラスは個別にテストできます。

  • OpportunityCalculator複雑な数学を抽象化します。
  • テスト中OpportunityFilterに、スタブアウトできますOpportunityCalculator。テストは、電卓が正しいパラメーターで 2 回参照されるという事実に集中します。
于 2013-06-16T17:10:51.440 に答える