38

例えばこちらの記事で紹介しています。

メリットは何ですか?

静的分析はクールに思えますが、同時に単体テストで null をパラメーターとして渡す機能を妨げます。(記事の例に従った場合)

単体テストのトピックについてですが、自動テストを既に実践している場合、現在の状況を考えると、コード契約の意味はありませんか?

アップデート

Code Contracts で遊んでみて、少しがっかりしました。たとえば、受け入れられた回答のコードに基づいて:

public double CalculateTotal(Order order)
{
    Contract.Requires(order != null);
    Contract.Ensures(Contract.Result<double>() >= 0);
    return 2.0;
}

単体テストでは、null が渡されないこと、およびコントラクトがビジネス ロジックの場合に結果がゼロ以上であることを確認するテストを作成する必要があります。つまり、最初のコントラクトを削除しても、特にこの機能のテストを行っていない限り、テストが壊れることはありません。ただし、これは、Visual Studio のより優れた (究極など) エディションに組み込まれている静的分析を使用しないことに基づいています。

基本的に、それらはすべて従来の if ステートメントを記述する別の方法に要約されます。Code Contracts を使用して TDDを実際に使用した私の経験は、その理由とその方法を示しています。

4

4 に答える 4

38

単体テストとコントラクトが互いに干渉することはあまりないと思います。無効な引数に対して退屈な繰り返しテストを追加する必要がなくなるため、コントラクトは単体テストに役立つはずです。コントラクトは関数から期待できる最小値を指定しますが、単体テストは特定の入力セットの実際の動作を検証しようとします。この不自然な例を考えてみましょう:


public class Order
{
    public IEnumerable Items { get; }
}

public class OrderCalculator
{
    public double CalculateTotal(Order order)
    {
        Contract.Requires(order != null);
        Contract.Ensures(Contract.Result<double>() >= 0);

        return 2.0;
    }
}

明らかにコードは契約を満たしていますが、実際に期待どおりに動作することを検証するために単体テストが必要です。

于 2009-09-05T15:35:03.650 に答える
27

メリットは何ですか?

メソッドが決して を返さないようにしたいとしましょうnull。単体テストでは、さまざまな入力でメソッドを呼び出し、出力が null でないことを確認する一連のテスト ケースを作成する必要があります。問題は、考えられるすべての入力をテストできないことです。

コード コントラクトでは、メソッドが を返さないことを宣言するだけですnull。静的アナライザーは、それを証明できない場合に文句を言います。問題がなければ、考えられるすべての入力に対してアサーションが正しいことがわかります。

作業が少なく、完全な正確性が保証されます。好きではないことは何ですか?

于 2009-09-06T00:17:30.450 に答える
4

コントラクトを使用すると、コンパイラまたはコードの次のリーダーの観点からの定義として立っているランダムな引数でコードが行うことを許可するのとは対照的に、コードの実際の目的が何であるかを言うことができます。これにより、静的解析とコードの最適化が大幅に向上します。

たとえば、(コントラクト表記を使用して) 整数パラメーターを 1 ~ 10 の範囲で宣言し、関数内に同じサイズを宣言したローカル配列があり、パラメーターによってインデックス付けされている場合、コンパイラーはそれを認識できます。添字エラーの可能性がないため、より良いコードが生成されます。

null はコントラクトで有効な値であると述べることができます。

単体テストの目的は、コードが宣言された目的を達成することを動的に検証することです。関数のコントラクトを作成したからといって、コードがそれを実行するわけではなく、静的解析でコードがそれを実行することを確認できるわけでもありません。単体テストはなくなりません。

于 2009-09-05T15:23:17.093 に答える
3

一般的に、単体テストを妨げることはありません。しかし、私が見たように、あなたは TDD について言及しました。

その観点から考えると、標準的な手順から変更する可能性がある/変更する可能性があると思います

  • create メソッド (署名のみ)
  • 単体テストの作成 -> テストの実装
  • テストを実行します: 失敗させます
  • メソッドを実装し、機能させるためだけに最後までハックします
  • テストを実行します: 合格することを確認してください
  • (おそらく面倒な)メソッド本体をリファクタリングします
  • (何も壊れていないことを確認するためだけにテストを再実行します)

これは、非常にハードでフル機能の単体テスト手順です。このようなコンテキストでは、次のように 1 番目と 2 番目のポイントの間にコード コントラクトを挿入できると思います

  • create メソッド (署名のみ)
  • メソッド入力パラメーターのコード コントラクトを挿入する
  • 単体テストの作成 -> テストの実装
  • ...

現時点で私が見ている利点は、定義済みのコントラクトによって一部が既に考慮されているため、考えられるすべてのパスをチェックする必要がないという意味で、より簡単な単体テストを作成できることです。追加のチェックを提供するだけですが、コード内には常により多くのロジックがあり、通常どおり単体テストでテストする必要があるパスが増えるため、単体テストに取って代わるものではありません。

編集

以前は考慮しなかった別の可能性は、リファクタリング部分にコード コントラクトを追加することです。基本的に、物事を保証する追加の方法として。しかし、それはどういうわけか冗長であり、人々は冗長なことをしたくないので...

于 2009-09-05T15:43:28.160 に答える