白盒テストは、ソフトウェアテストの典型的なシナリオの一つです。このシナリオでは、テスト担当者はプログラムのコードにアクセスし、コードの制御フローやデータフローなどの情報に基づいてテストケースを設計し、テストケースの実際の実行結果に基づいてプログラムが期待どおりであるか、バグが存在するか、テストケースの品質が高いかなどを判断することができます。
テストケースがテスト対象のプログラムを十分にテストしているかどうかを評価するために、一般的にコードカバレッジが使用されます。一般的に、テストケースができるだけ多くのコードを実行し、できるだけ多くのイベントをトリガーする場合、テストはより十分であると言えます。明らかなバグが発生しない場合、プログラムの品質は高くなり、実際のユーザーが入力する場合の振る舞いはより安定しています(ロバスト)。
プログラムのコードには通常、ループ、条件、関数呼び出しなどの特殊な構造が含まれています。これらの特殊な構造に対して異なるカバレッジルールを設計することにより、さまざまなコードカバレッジ基準を派生させることができます。一般的なものには次のようなものがあります。
- ステートメントカバレッジ
- ブランチカバレッジ(判定カバレッジ)
- 条件カバレッジ
- パスカバレッジ
次のプログラムを例にして説明します:
ステートメントカバレッジ#
ステートメントカバレッジ(ステートメントカバレッジ)は、実行されたコードの行数だけでカバレッジを測定します。カバレッジの分母はテスト対象のプログラムのソースファイルの総行数であり、分子はプログラムの実行中に通過したコード行数です。たとえば、サンプルプログラムには合計で 10 行のコードがあり、1 行目と 10 行目は必ず実行されます。入力 a = 2, b = 3, c = 2
を入力した場合、2 行目、3 行目、6 行目、7 行目が実行されるため、ステートメントカバレッジは 60%です。4 行目と 8 行目は排他的な関係にあるため、1 つの組み入力では 100%のステートメントカバレッジを達成することはできません。2 つの組み入力を作成することで、100%のステートメントカバレッジを達成できます:a = 2, b = 3, c = 4
および a = 2, b = 3, c = 1
。
ブランチカバレッジ(判定カバレッジ)#
ブランチカバレッジ(ブランチカバレッジ)は、条件判定を持つ文の各ブランチがカバーされることを要求します。コードの論理をフローチャートとして表現すると、ブランチカバレッジは直感的にはすべての接続と矢印がカバーされることを意味します:
連続して実行されるコードを 1 つのノードに統合すると、この図は次のように簡略化できます:
すべての接続と矢印をカバーする必要がありますが、通常は条件文とループ文によって生成されるブランチのみを考慮します。たとえば、2 行目の条件文では、2->3
と 2->6
の 2 つのブランチをカバーする必要があります。4 行目の条件文では、4->5
と 4->6
の 2 つのブランチをカバーする必要があります。
サンプルプログラムには合計で 4 つの条件文があり、4 つの真理値を取ることができます。入力 a = 2, b = 3, c = 2
の場合、実行後の各条件文の判定値は T, F, T, F
であり、それぞれの分岐 2->3, 3->6, 6->7, 7->10
に対応します。ブランチカバレッジ率を 100%にするには、判定値が F, T, F, T
になるような入力を作成するだけですが、サンプルプログラムでは、最初の条件が F になると、2 番目の条件が T になることはありません。次の 3 つの組み入力は、ブランチカバレッジ率を 100%にすることができます:
a = 2, b = 3, c = 2 => T, F, T, F
a = 10, b = 3, c = 4 => T, T, F, _
a = 1, b = 1, c = 1 => F, _, T, T
各判定が T と F の両方を取ることができるため、ブランチカバレッジの要件を満たします。
条件カバレッジ#
判定は通常、複数の条件(ブール値を生成する最小の式)を組み合わせて作成されるため、制御フローの変化をより細かく評価するために、上記のブランチカバレッジの判定の概念を置き換えるために、条件の値を使用して条件カバレッジを構成することができます。サンプルプログラムでは、2 行目のコードについては、a > 1 and b > 2
の値が T、F の場合ではなく、a > 1
と b > 2
の値がそれぞれ T、F の場合を考慮する必要があります。条件カバレッジでは、各条件が T と F の両方を取るだけで十分です。たとえば、1 つの入力が T、T を生成し、別の入力が F、F を生成する場合、条件カバレッジ率は 100%になります。ブランチカバレッジで提供された 3 つの組み入力では、次のように条件カバレッジ率を 100%にするために a < 1
の場合が欠けています。したがって、次の 3 つの組み入力を使用して条件カバレッジ率を 100%にすることができます:
a = 2, b = 3, c = 2 => T, F, T, F
a = 10, b = 3, c = 4 => T, T, F, _
a = 0, b = 1, c = 1 => F, _, T, T
パスカバレッジ#
パスカバレッジは、最も細かいカバレッジ基準であり、プログラムを入口(通常は main 関数)から出口(exit、panic、main 関数内の return 文)までの各文を組み合わせてパスを作成し、1 つの文でも異なる場合は異なるパスと見なします。サンプルプログラムに存在するパスは次のとおりです(見落としのないように願っています):
1,2->3,4->5->6->7,8->9->10
1,2->3,4->5->6->7,8->10
1,2->3,4->5->6->10
1,2->3,4->6->7,8->9->10
1,2->3,4->6->7,8->10
1,2->3,4->6->10
1,2->6->7,8->9->10
1,2->6->7,8->10
1,2->6->10
注意する必要があるのは、これはプログラムコードから分析されたすべての可能なパスであるということですが、実際の状況では、いくつかのパスは成立しません。たとえば、3,4->5
と 7,8->9
は同じパスには存在しないため、サンプルプログラムでは 100%のパスカバレッジを達成することは不可能です。
パスカバレッジは、これらのカバレッジ基準の中で最も要求が高いものであり、パスカバレッジを満たすと、他のすべてのカバレッジ(実際には存在しない場合を除く)も必ず満たすことができます。ただし、実際のプログラムには数え切れないほどの条件文、ループ文、およびこれらの組み合わせが含まれているため、パスの数は条件文とループ文の数の増加とともに指数関数的に増加し、高いパスカバレッジ率を達成することは非常に困難です。プログラムのコードが与えられた場合、存在するパスの数を計算することはほぼ不可能ですので、パスカバレッジを計算する際には比率ではなく数を数える方法を採用することが一般的です。異なるパスをトリガーするためのより多くの入力は、より高品質のテストケースと見なされます。