回答:
アサートは、プログラムの内部状態について通知するのに役立ちます。たとえば、データ構造に有効な状態があること、たとえば、Time
データ構造がの値を保持しないことなど25:61:61
。アサートによってチェックされる条件は次のとおりです。
発信者が契約を維持することを保証する前提条件、
呼び出し先が契約を維持することを保証する事後条件
不変式。関数が戻った後、データ構造が常に何らかのプロパティを保持することを保証します。不変条件は、前提条件および事後条件である条件です。
単体テストは、モジュールの外部動作について説明するのに役立ちます。あなたはStack
後に一貫性のある状態を有することができるpush()
メソッドが呼び出されますが、スタックのサイズは3で増加していない場合、誤りであることを3回、呼び出された後。(たとえば、誤ったpush()
実装がアサートと終了のみをチェックするという些細なケース。)
厳密に言えば、アサートと単体テストの主な違いは、単体テストにはテストデータ(プログラムを実行するための値)があるのに対し、アサートにはないことです。つまり、ユニットテストを自動的に実行できますが、アサーションに対して同じことを言うことはできません。この議論のために、高次機能テスト(プログラム全体を実行し、ユニットテストのようなモジュールを駆動しない)のコンテキストでプログラムを実行することについて話していると仮定しました。自動化された機能テストを「実際の入力を確認する」手段として話していない場合、価値は明らかに自動化にあるため、単体テストが勝ちます。(自動化された)機能テストのコンテキストでこれについて話している場合は、以下を参照してください。
テスト対象には重複する部分があります。たとえば、Stack
の事後条件は、実際にスタックサイズが1増加することを表明する場合があります。しかし、そのアサートで実行できることには制限があります。トップ要素が追加されたばかりのものであることも確認する必要がありますか?
両方の目標は、品質を向上させることです。単体テストの目標は、バグを見つけることです。アサーションの目標は、無効なプログラムの状態が発生するとすぐに監視することにより、デバッグを容易にすることです。
どちらの手法も正確性を検証しないことに注意してください。実際、プログラムが正しいことを確認する目的で単体テストを実施する場合、おそらく動作することがわかっている興味深いテストを思い付くでしょう。それは心理的な効果です。目標を達成するために何でもします。あなたの目標がバグを見つけることである場合、あなたの活動はそれを反映します。
どちらも重要であり、独自の目的があります。
[アサーションに関する最後の注意として:最大の価値を得るには、プログラムのすべての重要なポイントで使用する必要があり、いくつかの重要な機能ではありません。そうでない場合、問題の元のソースがマスクされ、何時間ものデバッグなしでは検出が困難になる可能性があります。]
アサーションについて話すときは、スイッチを押すだけでアサーションをオフにできることに注意してください。
非常に悪いアサーションの例:
char *c = malloc(1024);
assert(c != NULL);
なぜこれが悪いのですか?NDEBUGのようなものが定義されているためにそのアサーションがスキップされた場合、エラーチェックは行われないためです。
単体テストでは、上記のコードで(おそらく)セグメンテーション違反が発生します。確かに、何かがうまくいかなかったことを伝えることでその仕事をしましたか?malloc()
テストで失敗する可能性はどれくらいですか?
アサーションは、「通常の」イベントがアサーションを起動させないことをプログラマが示唆する必要がある場合のデバッグを目的としています。malloc()
失敗は、実際には通常のイベントであるため、決して主張されるべきではありません。
間違っている可能性のあるものを適切に処理する代わりに、アサーションが使用される他の多くのケースがあります。これが、アサーションが評判を落とす理由であり、Goのような言語にアサーションが含まれない理由です。
単体テストは、変更したものが他の何かを壊したときに通知するように設計されています。これらは、ビルドを行うたびに、プログラムのすべての機能(ただし、テスターはリリースにとって重要)を通過することから(ほとんどの場合)節約できるように設計されています。
両者が何かがおかしいと言ったことを除いて、実際には2つの間に明確な相関関係はありません。assertは、デバッガを使用せずに、作業中の何かのブレークポイントと考えてください。単体テストは、作業していないものを壊したかどうかを示すものと考えてください。
どちらも、構築しているシステムの全体的な品質の向上に役立つツールです。多くは、使用している言語、構築しているアプリケーションの種類、および時間を最もよく使用している場所に依存します。言うまでもなく、あなたはそれについていくつかの考え方を持っています。
まず、assert
キーワードのない言語を使用している場合、アサートを使用できません(少なくともここで説明している方法では使用できません)。長い間、Javaにはassert
キーワードがありませんでしたが、多くの言語にはまだありません。ユニットテストは、かなり重要になります。一部の言語では、アサーションはフラグが設定されている場合にのみ実行されます(ここでもJavaを使用)。保護が常に存在するとは限らない場合、あまり便利な機能ではありません。
あなたが何かを「アサート」している場合、if
/ throw
意味のある例外ブロックを書くこともできるという考え方があります。この思考プロセスは、すべての値が境界内にあることを保証するために、メソッドの先頭に配置された多くのアサートから来ています。前提条件をテストすることは、予想される事後条件を持つための非常に重要な部分です。
単体テストは、記述および保守が必要な追加のコードです。多くの人にとってこれは欠点です。ただし、現在の単体テストフレームワークのおかげで、比較的少ないコードでより多くのテスト条件を生成できます。パラメータ化されたテストと「理論」は、多数のデータサンプルを使用して同じテストを実行し、見つけにくいバグを発見できます。
個人的には、単体テストのほうが断定的な主張よりも多くのマイレージを獲得しますが、それは私がほとんどの時間に開発しているプラットフォーム(Java / C#)のためです。他の言語には、より堅牢なアサーションサポートがあり、さらに「Design by Contract」(以下を参照)でさえ、より多くの保証を提供します。これらの言語のいずれかを使用していた場合、単体テストよりもDBCを使用する可能性があります。
http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support
:-)