8

契約による設計手法をコーディングスタイルに取り入れようとしています。事後条件は、埋め込まれた単体テストのように私にはよく見えます。ここでの私の考えは、正しい方向に進んでいるのか、それともベースから外れているのか疑問に思っています。

ウィキペディアでは、事後条件を「コードの一部のセクションの実行直後、または正式な仕様での操作後に常に真でなければならない条件または述語。事後条件は、コード自体の中でアサーションを使用してテストされる場合があります」と定義しています。

これは、状態を直接検証する(モックを使用しない)単体テストで行うこととあまり似ていませんか?

だとしたら:

1)事後条件を使用することで、テストコードを本番コードに埋め込んでいるのではないでしょうか。また、それは眉をひそめているのではないでしょうか。

2)事後条件を使用すると、単体テストの構造を変更する必要がありますか?私の最初の考えは、アサーションロジックがテストから事後条件に移行することです。つまり、テストは同じ入力を使用し、以前にテストしていたすべてのものをテストしていますが、単体テストでアサーションを作成する代わりに、事後条件が合格するかどうかについて単純なバイナリアサーションを作成しています。

3)私の第二の考えは、事後条件コードには制御フローがある可能性があるため、単純で制御フローを回避することになっているテストコードには理想的ではないということです。しかし、事後条件をテストする場合、単体テストでそれらを信頼できますか?

4)事後条件をテストするのは難しいようです。正しく理解すれば、基本的に合格または不合格であり、事後条件自体のロジックを繰り返して、それが正しいことを確認する必要があるためです。では、どのように事後条件をテストしますか?単体テストでそれらを利用せず、単体テストと事後条件が一緒に合格または不合格になることを確認して、それらをチェックしますか?

5)ユニットテストでは、メソッドによって共同作業者の状態が変化したことが確認されることがあります。標準的な方法では、事後条件はコラボレーターの状態をカバーしますか、それともそれらが定義されているクラスの状態のみをカバーしますか?

4

3 に答える 3

5

あなたは正しい軌道に乗っています。

事後条件が単体テストと同様の目的を果たすことは事実です。主な違いは、事後条件は常に実行されるのに対し、単体テストは既知のデータ セットに対してのみ実行されることです。これは、事後条件が思いもよらなかったコーナーケースを見逃す可能性が低いことを意味しますが、実行時のコストが高くなります。

ここでは、特定の質問に対する回答を示します。

  1. 事後条件には実行時のペナルティがあります。ただし (環境によっては)、速度のためにアサーションをドロップできる場合があります。(C では #ifdef を使用でき、Java では AOP をルックアップし、Python ではassert--debug フラグを渡した場合にのみ実行されます。) アサーションからパフォーマンスの問題が発生した場合、それは解決可能です。ただし、そうしない理由がわかるまでは、そのままにしておくことをお勧めします。

  2. ロジックの一部は、単体テストから事後条件に自然に移行します。ただし、事後条件に関係するすべてのケースを実行する単体テストがあることを確認することは価値があります。これは、速度のために本番環境でアサーションを削除する場合に特に当てはまります。

  3. 事後条件は単体テストではありません。それらが何をするかについて意味のある方法でそれらを書きます。(一般的に、それらは幾分単純であるべきです。)

  4. 一般に、#2 で説明したように、事後条件に違反している可能性がある対象の入力のセットを渡すことによって事後条件をテストし、違反していないことを確認します。事後条件自体のロジックをテストする場合は、事後条件に違反する可能性があるが、テスト中にのみ実行されるコードを設定できます。たとえば、テストで設定できるグローバル変数があり、設定されている場合は、返されるデータを必要なものに置き換えます。これで、事後条件に任意の入力を受け取ることができます。

  5. 私はあなたに厳しいルールを与えるつもりはありません。それらはあなたの契約です。彼らは、関数が何をしているのかについて何が理にかなっているのかを言うべきです. とはいえ、あなたが説明していることは、それらのオブジェクト間の密結合につながる可能性があります。密結合は、正当な理由がある場合にのみ行うべきものです。

于 2011-02-20T15:20:30.503 に答える
2

コントラクトは単体テストの形式ではありません。むしろ、特定の関数またはメソッドが呼び出される前後に保持する必要がある条件を (実行可能な形式で) 指定する方法であり、オブジェクトの不変条件を指定することもできます。

関数が何をすべきかを指定したからといって、実際にそれを行うとは限らないため、コントラクトがある場合でもテストが必要です。しかし、コントラクトがデバッグに役立つことがわかります。なぜなら、実行時に何が起こっているかをチェックできるコードがあるということは、ロジックまたはプログラミング エラーがエラーを含むコードの近くで失敗を引き起こすことを意味するからです。 .

コントラクトを使用すると、テストが広範囲であっても、コントラクトによってエラーの原因を絞り込むことができるため、小規模なテストを減らして大規模なテストを行うことができます。また、単体テストがロジックの動作方法の仕様の役割を果たす必要性が少なくなり、小規模なテストの価値がさらに制限されます。

コントラクトは、運用コードで有効にするかどうかを選択できるという点で、アサーションに似ています。私の意見では、コントラクトはアサーションよりもコストがかかる傾向があるため、本番環境ではコントラクトを無効にする傾向があります。

于 2011-02-20T15:07:20.793 に答える
0

あらゆる方法論やコーディング スタイルと同様に、正解は 1 つではありません。ただし、これまでのところ真実であることがわかっていることの 1 つは、「1 つのサイズですべてに適合する」ソリューションは決してないということです。

したがって、これらのアサーションを設計のすべての事後条件のロジックに実装するとしたら、それは間違っていると思います。

私自身の意見では、このようなアサーションは、事後条件を満たさないためにシステム全体が危険なほど一貫性のない状態になる場合にのみ使用する必要があります。したがって、そのようなことが起こった場合、私は間違いなくシステムに次のようなことをしてもらいたいと思います: 管理者に電子メール/SMS を送信する、本番環境の実行を停止する、診断を実行する、またはその特定のシステムに対して行うべきことは何でもします。これは、セキュリティの強化を目的とした実際の機能であり、単体テスト コードではないことに注意してください。

一方、すべてのメソッド呼び出しの後にアサーションをコーディングしている場合、お気づきのように、テスト ケースを製品コードにハードコーディングするだけです。コードベースをめちゃくちゃにする以外に、それは本当の目的には役立ちません。

于 2011-02-20T15:06:06.573 に答える