web-dev-qa-db-ja.com

Debug.Assertとコードコントラクトの使用

いつコードコントラクトに対してdebug.assertをデバッグする必要がありますか?メソッドの前提条件を確認したいのですが、どちらを選択するか混乱しています。失敗シナリオをテストし、例外を予期する単体テストがあります。

同じメソッドでDebug.Assertとコードコントラクトを使用することは良い方法ですか?もしそうなら、コードが書かれるべき順序は何ですか?

Debug.Assert(parameter!= null);
Contract.Requires<ArgumentNullException>(parameter != null, "parameter");

または

Contract.Requires<ArgumentNullException>(parameter != null, "parameter");
Debug.Assert(parameter!= null);

その背後に根拠はありますか?

42
Carbine

これらは異なるものです。デバッグアサートは、コードがデバッグとしてコンパイルされたときにのみ実行されるため、デバッグ時にのみチェック/アサートします。これは、開発中のコードの「健全性チェック」にこれを使用するという考え方です。コードコントラクトは、デバッグまたはリリースで使用できます。彼らは、メソッドの事前条件と事後条件がメソッドの期待に準拠している(契約を満たす)ことを保証します。テストのコンプライアンスをチェックするために設計された、同様の機能を提供するテストフレームワークもあります。

コードの開発時(およびその後のメンテナンス開発時)に特定のものが期待どおりであることを確認したい場合は、Debug.Assertを使用します。

デバッグとリリースの両方で条件が満たされていることを確認する場合は、コードコントラクトを使用します。コントラクトでは、プログラムが「正しい」ことを確認するのに役立つ特定の形式の静的分析も許可されます。

単体テストを作成するときは、テストフレームワークアサーションを使用します。

34
Dweeberly

個人的に、私は_Debug.Assert_とコードコントラクトの両方を使用して、新しく記述されたコードの前提条件を適用しません-IMOコードコントラクトは_Debug.Assert_に優先します。コードが実行時になる前に実行できる静的チェックから取得できます。 _Debug.Assert_とContractsの両方で前提条件チェックの重複を維持するのは面倒です。

根拠:

  • _Debug.Assert_またはthrowコードでコーディングしたレガシーの前提条件を再コーディングする必要はありません。既存の前提条件チェックコードを保持し、 Contract.EndContractBlock()
  • _System.Diagnostics.Debug_なしで_/d:DEBUG_をビルドする場合、コントラクトランタイムチェックをNoneに設定してビルドすると、同じ未チェックの「リリースモード」の動作が得られます。 ドキュメントの6.2.1を参照
  • コントラクトを使用すると、無効な状態が検出された「理由」について、コードでより表現力を高めることができます。帯域外パラメータ(_Contract.Requires_)が直接原因でした。それ以外の場合、_Contract.Assert_または_Contract.Assume_は一般的な状態をチェックでき、メソッドを終了するときの状態の「保証された正確さ」は_Contract.Ensures_を使用して表現できます。そして、Invariantsは、常に状態を保持しなければならないことを表しています。
  • そして何よりも、静的チェックは、コードをビルドするときにこれらのコントラクトを強制できます。これにより、ランタイムを待たずに、設計時またはコンパイル時の警告を通じてバグを拾うことができます。継続的インテグレーションに契約チェックを追加して、非準拠を探すことができます。

注意点の1つ:意図的に契約に違反する単体テストを作成する場合は、ContractExceptionに対処する必要があるかもしれません-Jon Skeetがこれをうまく説明しています here 。例えばテストセットアップの _Contract.ContractFailed_ハンドラーSetHandledを呼び出すハンドラーに接続し、UTでキャッチしてアサートできるパブリック例外をスローします。

26
StuartLC