アサートまたは単体テストはより重要ですか?


51

アサートと単体テストの両方は、コードベースのドキュメントとして、またバグを発見する手段として機能します。主な違いは、アサートが健全性チェックとして機能し、実際の入力を確認するのに対して、ユニットテストは特定のシミュレートされた入力で実行され、明確に定義された単一の「正しい答え」に対するテストです。正当性を検証する主な手段として、アサーションと単体テストを使用する相対的なメリットは何ですか?どちらをもっと強調すべきだと思いますか?


4
私はこのアイデアがとても好きです...とても気に入ったので、このトピックをソフトウェアのテストと品質保証コースの課題にしています。:-)
マクニール

もう1つの質問は、アサーションを単体テストする必要がありますか?;)
mojuba

回答:


43

アサート、プログラムの内部状態について通知するのに役立ちます。たとえば、データ構造に有効な状態があること、たとえば、Timeデータ構造がの値を保持しないことなど25:61:61。アサートによってチェックされる条件は次のとおりです。

  • 発信者が契約を維持することを保証する前提条件、

  • 呼び出し先が契約を維持することを保証する事後条件

  • 不変式。関数が戻った後、データ構造が常に何らかのプロパティを保持することを保証します。不変条件は、前提条件および事後条件である条件です。

単体テスト、モジュールの外部動作について説明するのに役立ちます。あなたはStack後に一貫性のある状態を有することができるpush()メソッドが呼び出されますが、スタックのサイズは3で増加していない場合、誤りであることを3回、呼び出された後。(たとえば、誤ったpush()実装がアサートと終了のみをチェックするという些細なケース。)

厳密に言えば、アサートと単体テストの主な違いは、単体テストにはテストデータ(プログラムを実行するための値)があるのに対し、アサートにはないことです。つまり、ユニットテストを自動的に実行できますが、アサーションに対して同じことを言うことはできません。この議論のために、高次機能テスト(プログラム全体を実行し、ユニットテストのようなモジュールを駆動しない)のコンテキストでプログラムを実行することについて話していると仮定しました。自動化された機能テストを「実際の入力を確認する」手段として話していない場合、価値は明らかに自動化にあるため、単体テストが勝ちます。(自動化された)機能テストのコンテキストでこれについて話している場合は、以下を参照してください。

テスト対象には重複する部分があります。たとえば、Stackの事後条件は、実際にスタックサイズが1増加することを表明する場合があります。しかし、そのアサートで実行できることには制限があります。トップ要素が追加されたばかりのものであることも確認する必要がありますか?

両方の目標は、品質を向上させることです。単体テストの目標は、バグを見つけることです。アサーションの目標は、無効なプログラムの状態が発生するとすぐに監視することにより、デバッグを容易にすることです。

どちらの手法正確性を検証しないことに注意してください。実際、プログラムが正しいことを確認する目的で単体テストを実施する場合、おそらく動作することがわかっている興味深いテストを思い付くでしょう。それは心理的な効果です。目標を達成するために何でもします。あなたの目標がバグを見つけることである場合、あなたの活動はそれを反映します。

どちらも重要であり、独自の目的があります。

[アサーションに関する最後の注意として:最大の価値を得るには、プログラムのすべての重要なポイントで使用する必要があり、いくつかの重要な機能ではありません。そうでない場合、問題の元のソースがマスクされ、何時間ものデバッグなしでは検出が困難になる可能性があります。]


7

アサーションについて話すときは、スイッチを押すだけでアサーションをオフにできることに注意してください。

非常に悪いアサーションの例:

char *c = malloc(1024);
assert(c != NULL);

なぜこれが悪いのですか?NDEBUGのようなものが定義されているためにそのアサーションがスキップされた場合、エラーチェックは行われないためです。

単体テストでは、上記のコードで(おそらく)セグメンテーション違反が発生します。確かに、何かがうまくいかなかったことを伝えることでその仕事をしましたか?malloc()テストで失敗する可能性はどれくらいですか?

アサーションは、「通常の」イベントがアサーションを起動させないことをプログラマが示唆する必要がある場合のデバッグを目的としています。malloc()失敗は、実際には通常のイベントであるため、決して主張されるべきではありません。

間違っている可能性のあるものを適切に処理する代わりに、アサーションが使用される他の多くのケースがあります。これが、アサーションが評判を落とす理由であり、Goのような言語にアサーションが含まれない理由です。

単体テストは、変更したものが他の何かを壊したときに通知するように設計されています。これらは、ビルドを行うたびに、プログラムのすべての機能(ただし、テスターリリースにとって重要)を通過することから(ほとんどの場合)節約できるように設計されています。

両者が何かがおかしいと言ったことを除いて、実際には2つの間に明確な相関関係はありません。assertは、デバッガを使用せずに、作業中の何かのブレークポイントと考えてください。単体テストは、作業していないものを壊したかどうかを示すものと考えてください。


3
そのため、アサーションは常にエラーテストではなく真のステートメントであると想定されています。
ドミニクマクドネル

@DominicMcDonnellええと、「本当のはず」のステートメント。バグのあるabs()が組み込まれているgccの特定のバージョンなど、コンパイラーの癖を回避することを断言することがあります
ティムポスト

そして、ここで私は、生産コードが最もアサートを必要とする場所だと思います。なぜなら、それは、あなたが不可能だと思った入力を得る生産であるからです。プロダクションは、最も難しいバグをすべて駆除する場所です。
フランクシェラー

@フランク・シェラー、非常に真実。本番環境で最も早く検出されたエラー状態で、まだハードに失敗しているはずです。ユーザーが文句を言うことは確かですが、それがバグが修正されることを確認する唯一の方法です。また、後でいくつかの関数呼び出しをnullに逆参照するためのメモリ例外よりも、何とか0を取得する方がはるかに優れています。
ドミニクマクドネル

一般的な(ユーザーの目には)まれな問題を、決して発生してはならないと断言するのではなく、対処する方がよいのはなぜですか?私はこの知恵に気づきません。確かに、素数ジェネレーターが素数を返すことをアサートします。素数はデバッグビルドで予想される余分な作業を必要とします。言語がネイティブにテストできるものをアサートするのは、まあ、愚かです。これらのテストを、リリース後数か月でオフにできる別のスイッチでラップすることはありません。
ティムポスト

5

どちらも、構築しているシステムの全体的な品質の向上に役立つツールです。多くは、使用している言語、構築しているアプリケーションの種類、および時間を最もよく使用している場所に依存します。言うまでもなく、あなたはそれについていくつかの考え方を持っています。

まず、assertキーワードのない言語を使用している場合、アサートを使用できません(少なくともここで説明している方法では使用できません)。長い間、Javaにはassertキーワードがありませんでしたが、多くの言語にはまだありません。ユニットテストは、かなり重要になります。一部の言語では、アサーションはフラグが設定されている場合にのみ実行されます(ここでもJavaを使用)。保護が常に存在するとは限らない場合、あまり便利な機能ではありません。

あなたが何かを「アサート」している場合、if/ throw意味のある例外ブロックを書くこともできるという考え方があります。この思考プロセスは、すべての値が境界内にあることを保証するために、メソッドの先頭に配置された多くのアサートから来ています。前提条件をテストすることは、予想される事後条件を持つための非常に重要な部分です。

単体テストは、記述および保守が必要な追加のコードです。多くの人にとってこれは欠点です。ただし、現在の単体テストフレームワークのおかげで、比較的少ないコードでより多くのテスト条件を生成できます。パラメータ化されたテストと「理論」は、多数のデータサンプルを使用して同じテストを実行し、見つけにくいバグを発見できます。

個人的には、単体テストのほうが断定的な主張よりも多くのマイレージを獲得しますが、それは私がほとんどの時間に開発しているプラ​​ットフォーム(Java / C#)のためです。他の言語には、より堅牢なアサーションサポートがあり、さらに「Design by Contract」(以下を参照)でさえ、より多くの保証を提供します。これらの言語のいずれかを使用していた場合、単体テストよりもDBCを使用する可能性があります。

http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.