以前のコラムで、ソースコードのカバレッジについてご紹介しました。その中でC0、C1、C2といったカバレッジ基準について解説しましたが、それ以外にも目的や用途に合わせたカバレッジ基準が存在します。
カバレッジ基準、特にコードカバレッジはシステムの品質を考える上では知っておくべき考え方ですが、カバレッジに固執しすぎると起こりうる弊害もあります。
今回の記事では、カバレッジ基準を一挙にご紹介するとともに、コードカバレッジを考えていくにあたって気をつけたい「カバレッジの罠」とも言える事例を紹介いたします。
コードカバレッジ大全集
コードカバレッジに焦点を絞り、具体的なコードを明示しながらカバレッジの特徴を解説します。今回ご紹介するのは、下記の代表的な7種類のカバレッジです。
- ステートメント・カバレッジ(C0)
- デシジョンカバレッジ(C1)
- コンディションカバレッジ
- コンディション/デシジョン・カバレッジ
- MC/DC
- 複合条件カバレッジ(C2)
- パスカバレッジ
1.ステートメント・カバレッジ(C0)
命令網羅とも言われます。これは、プログラム上の全ての命令文を実行することがカバレッジを向上させることに直結するという考え方です。
コード例1
commandA(); if (x == 0) { // 変数xの値が0のとき、{}の中を実行 commandB(); } commandC(); |
ステートメント・カバレッジを100%にする方法
変数x=0のテストケースを実行すれば、全ての命令文(CommandA,B,C)が実行されます。この考え方に則れば、テストケースは1パターンで良いことになります。
2.デシジョンカバレッジ(C1)
判断網羅、またはブランチカバレッジとも言われます。プログラム上の全ての判断文について、その判断結果すべてを網羅するように実行する考え方です。
コード例2
commandA(); if (x == 0) { // 変数xの値が0のとき、{}の中を実行 commandB(); } commandC(); |
デシジョンカバレッジを100%にする方法
変数xが「0の場合」「0以外の場合」の2種類のテストケースを実行すれば、if文の条件のTRUE/FALSEの両方を網羅できます。この考え方に則れば、テストケースは2パターンで良いことになります。
3.コンディションカバレッジ
条件網羅とも言われます。プログラム上の全ての判断文について、判断文内の条件式ひとつひとつを網羅しすべてのパターンを実行する考え方です。
コード例3
commandA(); if (x == 0 || y <= 10) {??? // ||は「または」の意味 commandB(); } commandC(); |
デシジョンカバレッジを100%にする方法
この場合、判断式は「x == 0」と「y <= 10」のそれぞれ2種類です。
変数 |
値 |
条件 x == 0 |
条件 y <= 10 |
x |
0 |
TRUE (a) |
- |
0以外の数字 |
FALSE (b) |
- |
|
y |
10以下 |
- |
TRUE (c) |
10より大きい |
- |
FALSE (d) |
デシジョンカバレッジの考え方では、各条件式について、真偽の判定を網羅できればOKです。
つまり、
「x = 0, y = 100」... 「パターン(a):TRUE」かつ「パターン(d):FALSE」
「x = 1, y = 0」 ... 「パターン(b):FALSE」かつ「パターン(c):TRUE」
の2種類のテストケースを実行すれば、コンディションカバレッジは100%になります。
4.コンディション/デシジョン・カバレッジ
条件判断網羅、デシジョン/コンディション・カバレッジ、判断条件網羅とも言われます。これは、デシジョンカバレッジ、コンディション・カバレッジの両方をカバーする考え方です。
つまり、コンディション・デシジョンのどちらか一方を網羅したとしてももう一方を網羅できるとは限らない、といった難点をカバーできます。コンディションとディシジョンの両方のカバレッジを向上させるために重要な考え方です。
コード例4
commandA(); if (x == 0 || y <= 10) {??? // ||は「または」の意味 commandB(); } commandC(); |
コンディション/デシジョンカバレッジを100%にする方法。 この考え方では、各条件式について、真偽の判定と判断式の結果を網羅する必要があります。
変数 |
値 |
条件 x == 0 |
条件 y <= 10 |
x |
0 |
TRUE (a) |
- |
0以外の数字 |
FALSE (b) |
- |
|
y |
10以下 |
- |
TRUE (c) |
10より大きい |
- |
FALSE (d) |
つまり、上記に加えて下記を考慮する必要があります。
x == 0 のパターン |
y <= 10 のパターン |
判断式の真偽 |
TRUE (a) |
TRUE (c) |
TRUE (A) |
FALSE (d) |
TRUE (B) |
|
FALSE (b) |
TRUE (c) |
TRUE (C) |
FALSE (d) |
FALSE (D) |
したがって、
「x = 0, y = 0」 ... 「パターン(a):TRUE」かつ「パターン(c):TRUE」→TRUE(A)
「x = 1, y = 100」... 「パターン(b):FALSE」かつ「パターン(d):FALSE」→FALSE(D)
の2種類のテストケースを実行すれば、デシジョン/コンディションカバレッジは100%になります。
5.MC/DC
Modified Condition/Decision Coverage の略です。改良条件判断網羅と訳されます。
前述したコンディション/デシジョン・カバレッジを利用した場合でもデシジョン・カバレッジと同程度のカバレッジとなってしまうので、より詳細で綿密なカバレッジ網羅を行う必要がある場合に、MC/DCを使用します。
特に、DO-178B(RTCA)といった、航空機器の安全基準などでこの考え方を用いるよう、設定されています。
DO-178Bの定義によると、MC/DCカバレッジを100%にするには、下記の条件を満たす必要があります。
- 判断文がすべての結果を実行する
- 条件式がすべてのパターンを実行する
- 条件式の各条件が、単独で結果に影響する
1.と2.はコンディション/デシジョン・カバレッジと同等の基準ですが、この2つに3.を追加することによって、より詳細なカバレッジを実現することができます。
コード例5
commandA(); if (x == 0 || y <= 10) {??? // ||は「または」の意味 commandB(); } commandC(); |
MC/DCを100%にする方法
デシジョン/コンディションカバレッジと同様に、各条件式について真偽の判定と判断式の結果を網羅するという点は変わりません。
これに加え、条件式が単独で判断結果に影響するようなパターンを選択する必要があります。
x == 0 のパターン |
y <= 10 のパターン |
判断式の真偽 |
TRUE (a) |
TRUE (c) |
TRUE (A) |
FALSE (d) |
TRUE (B) |
|
FALSE (b) |
TRUE (c) |
TRUE (C) |
FALSE (d) |
FALSE (D) |
したがって、
「x = 0, y = 100」... 「パターン(a):TRUE」かつ「パターン(d):FALSE」→TRUE(B)
「x = 1, y = 0」 ... 「パターン(b):FALSE」かつ「パターン(c):TRUE」→TRUE(C)
「x = 1, y = 100」... 「パターン(b):FALSE」かつ「パターン(d):FALSE」→FALSE(D)
の3種類のテストケースを実行すれば、MC/DCは100%になります。
残った
「パターン(a):TRUE」かつ「パターン(c):TRUE」→TRUE(A)
については、条件式の真偽変更しても判断結果が変わらないため、MC/DCの3.の条件を満たしません。よって、テストケースに含める必要はない、と判断できます。
6.複合条件カバレッジ(C2)
マルチコンディション・カバレッジとも言います。すべての条件式の組合せを実行する考え方です。
単独の判断文に対するカバレッジの中ではもっとも網羅性の高い基準ですが、条件式が増えるほどテストケース数が極端に増えていくという欠点もあります。
コード例6
commandA(); if (x == 0 || y <= 10) {??? // ||は「または」の意味 commandB(); } commandC(); |
MC/DCを100%にする方法
x == 0 のパターン |
y <= 10 のパターン |
判断式の真偽 |
TRUE (a) |
TRUE (c) |
TRUE (A) |
FALSE (d) |
TRUE (B) |
|
FALSE (b) |
TRUE (c) |
TRUE (C) |
FALSE (d) |
FALSE (D) |
全ての条件式の組み合わせを網羅する必要があるため、上記表に表した4つのパターン全てを実行する必要があります。
7.パス・カバレッジ
ここまで紹介してきた1~5のカバレッジは、単独の判断文に対するカバレッジ率を表現しています。これに対して、プログラムの一定の範囲(関数やクラスなど)に対するすべての経路(パス)を網羅するかどうかの基準がパス・カバレッジとなります。
そのため、プログラム内に判断文が増えれば増えるほど、テストケース数が極端に増えていってしまいます。 特に、for文・while文などのループを含むプログラムの場合は、実質的に100%網羅は困難となります。
コードカバレッジの落とし穴
カバレッジには様々な種類があり、どのような観点で網羅性を高めるかによって達成できる品質や保証内容が異なることがわかりました。カバレッジを100%に近づけることはテストケースの品質をあげるにあたって非常に大切な観点ですが、それだけでは不十分です。
なぜなら、カバレッジの向上を達成したとしても、実際にテストケースを振り返って保証できた内容を見てみると、システムに求める品質として不十分な場合があるからです。
例えば、下記のような命令文があるとします。
int a = b / c; |
この例は、「b÷cの結果をaに代入する」という命令文です。
ですので、例えばbに10, cに5を設定するようなテストケースを実行すれば、カバレッジは100%となります。
ただし、cが0の場合、ゼロ除算のエラーが発生します。つまり、カバレッジが100%になっただけではエラーの考慮ができておらず、十分な品質保証ができないと言えます。
エラーが発生するのをcが0とならないことをどこかで担保する必要がありますが、カバレッジだけに着目していた場合は、この観点を確認できなくなる恐れがあります。
また、カバレッジの説明でこれまで例に挙げてきたコード例について考えてみてください。
commandA(); if (x == 0 || y <= 10) {??? // ||は「または」の意味 commandB(); } commandC(); |
プログラム言語や構造によっては、「x == 0」が真の場合には、「y <= 10」の部分を判断しないものもあります。このような仕組みを「遅延評価」と呼びます。
この場合はyの値を評価することなく、「x == 0」の部分だけでカバレッジを100%とすることができてしまうので、実際に実施するテストとしては不十分になることも考えられます。
このような「カバレッジの罠」にはまらないためにも、カバレッジの網羅性にばかり着目しすぎない方が良いこともあるでしょう。カバレッジの観点で作成したテストケースの内容が、システム全体として品質保証を十分にできているか、確認が必要です。
おわりに
今回の記事では、代表的なカバレッジの種類について具体的なコード例を挙げて解説したうえで、カバレッジを扱うにあたって気をつけるべきポイントについて説明してきました。カバレッジ、特にコードカバレッジは、条件式とその判断結果を中心に網羅性をあげる、ホワイトボックステストを実施するにあたって非常に重要な観点です。
どの程度の網羅性を達成すべきかによってテストケースの選び方がそれぞれ変わりますので、それらの特徴を踏まえてカバレッジの手法を選択する必要があるでしょう。
ただし、カバレッジの考え方ではカバーしきれない観点は意外と多くあります。カバレッジを達成したテストケースがシステムの性質上保証すべき観点を押さえているか、毎回確認する必要があると言えるでしょう。