私は最近、修士プログラムのソフトウェアエンジニアリングコースの最終試験を受けました。試験の質問の1つは次のとおりです。
Unit Testing is considered:
a. White-box Testing
b. Black-box Testing
c. Either
7年間のソフトウェア開発経験の中で、ユニットテストは常にホワイトボックスアプローチを採用してきました。テスターは、テストを作成する間、常にユニットの実装について完全な知識を持っています。ブラックボックステストは常に、統合、システム、および受け入れテストの形式で後から行われました。
ただし、(教授によると)試験に対する正解は、単体テストはホワイトボックステストまたはブラックボックステストのいずれかであるということです。
私はいくつかの調査を行いましたが、多くの場合「ブラックボックスユニットテスト」は、コードが作成される前にユニットテストが記述されるテストファーストアプローチを説明するために使用されているようです。しかし、私の意見では、これはまだホワイトボックステストです。実装はまだ存在していませんが、テストを書いている人は一般に、ソースコードの実装方法についてかなり良い考えを持っています。
ブラックボックスユニットテストのしくみ(本当にそうである場合)とホワイトボックスユニットテストとの違いを誰かに説明してもらえますか?
あなたの教授は正しいです:単体テストはブラックボックスまたはホワイトボックスのいずれかです。違いは、テスターが知っていることではなく、テストケースを生成する方法です。
ブラックボックステストでは、インターフェースと(存在する場合)コンポーネントの仕様のみを確認します。関数にシグネチャint foo(int a, int b)
がある場合、興味深い整数をテストするだけで、いくつかのテストケースをすぐに生成できます:0、1、マイナス1、複数桁の数値、INT_MAX、INT_MAX-1など。ブラックボックステストは、実装から独立しているため優れています。しかし、彼らはまた、重要なケースを見逃すかもしれません。
ホワイトボックステストでは、実装、つまりソースコードを確認し、そこからテストケースを生成します。たとえば、関数のパスカバレッジを100%にしたいとします。次に、すべてのパスが選択されるように入力値を選択します。ホワイトボックステストは、ブラックボックステストよりもはるかに自信を持ってコードの一部を徹底的に実行できるため、優れています。ただし、実装の詳細をテストするだけで、実際には重要な動作ではない場合があります。場合によっては、明らかに時間の無駄です。
ホワイトボックステストは実装から派生しているため、後でしか記述できません。ブラックボックステストは、設計/インターフェイス/仕様から導出されるため、実装の前または後に記述できます。 TDDは明らかにブラックボックスでもホワイトボックスでもありません。すべての動作は最初にテストで表現され、次にその動作の最小限のコードが実装されるため、TDDはホワイトボックステストと同様のテストケースになります。しかし、情報フローを見ると、TDDテストはソースコードからではなく、外部の要件から派生しています。したがって、TDDはよりブラックボックスのようなものです。
テスト駆動開発を行っている場合、理論的には理論的にはすべてのユニットテストはブラックボックスである必要があります。これが「テストファーストアプローチ」です。コントラクト(インターフェイス)を作成し、そのコントラクトのテストを作成すると、実装によってコントラクトが実行されます。したがって、テストは実装について何も知らず、何も知らないはずです。
結局、テストを書くとき、何をテストしていますか?パブリックメソッド/関数。
クラスのインターフェースを作成してからテストを作成し、その後バスにぶつかった場合、入院中にクラスを作成する人はインターフェースからそうすることができるはずですよね?彼はそれを捨てて、彼自身のインターフェースとテストを書く必要はありません。
これが多少ばらつくのは、実装に依存するものをモックする必要がある場合ですが、決して公開されていないものをモックしている状況にいると、間違いを犯し、 Dependency Injectionet alを参照してください。したがって、私は黒ではなく、ホワイトボックスのユニットテストが例外であるべきだと主張します。
'トイレでのテスト-テスト動作が実装ではない' を検討してください。クラスの実装は変更されていますが、テストは引き続き有効です。
ただし、コードカバレッジがアップしていることを確認する必要がある場合(つまり、すべての条件付きパスが実装内でテストされていることを確認する必要がある場合)、ユニットテストをホワイトボックスで行う必要があります。パスは、実装のパスを見ることです。
よく書かれた単体テストはすべて本質的に「ブラックボックス」であると私は主張します。確かに、テストを作成するときに実装を念頭に置いているかもしれませんが、その実装はリファクタリングすると変わる可能性があります。したがって、テストでは、実装ではなく機能をテストするために、テスト中にのみパブリックAPIを使用する必要があります。実装の詳細は関係ないため、ブラックボックステストを行います。
テスト対象のユニットの内部またはプライベートな側面にアクセスするテストを作成する場合は、実装の詳細をテストします。つまり、ホワイトボックステストです。しかし、実装が変更されたときに簡単に壊れる可能性のある、もろいテストも書いています。したがって、このようなホワイトボックステストは悪い考えであり、避ける必要があります。
結論:ユニットテストを使用したホワイトボックステストの場合、テストの構成が不十分です。それらの単体テストでのバックボックステストのみ。あなたの教授は正しいです:それはどちらでもかまいません。しかし、ひどい場合にのみ。
私はブラックボックステストを実行する単体テストを作成している最中でした。つまり、私はクラスでパブリックメソッドをテストし、それらが呼び出すプライベートメソッドで結果テストロジックを暗黙的にテストしています。
私はこれを行うために、ユニットテストされるパブリックメソッドへの入力を変更し、サポートされるプライベートメソッドのロジックによって決定または変更される予想出力をテストします。
したがって、単体テストでブラックボックステストを実行するのを妨げるものは何もありません。誰かが隠されたサポートロジックの実装に手を加えると、テストが中断します。実際、これはクラスのすべてをテストするためのホワイトボックスユニットよりも優れた効率的なアプローチのようです。私は教授と一緒です。