☪️

分岐カバレッジ(C1/C2)とgcovのカバレッジの違い

2023/12/03に公開

プログラムを開発していると、テストが十分かどうかを確認するためにコードカバレッジに関する品質目標が設定される場合があります。その際、日本の会社だと多くの場合に基準としてC0/C1/C2などの用語が使われていて、C1/C2がいわゆる分岐カバレッジになるのですが、これらの定義と gcov の考え方が少し異なるので違いについてシェアしようと思います。

C1カバレッジ・C2カバレッジの定義について

この用語は広く使われている割に定義を定めた標準規格がなさそうです[1]。そのためか、経験上様々な定義が行われているようなのですが、今回は一番簡単な以下の定義を採用します。

これらの定義では、ソースコードの分岐を基準に考えられているのが特徴です。

説明には以下の疑似コードを利用します(C言語風)。

statement1;
if (condition1 || condition2) {
  statement2;
}
if (condition3) {
  statement3;
}

C1カバレッジ

この記事における C1カバレッジは以下の定義です:

  1. サンプルコードにおける if 文のあとの括弧の中身を 条件文 と呼ぶことにします。各 条件文 はTRUE or FALSEの結果を持ち、その結果が命令文(statement1 〜 3)の実行順序の分岐を起こします。
  2. C1カバレッジではすべての 条件文 において、分岐の双方をカバーしたかを計測します。
  3. この際、条件文 間の組み合わせなどは考慮しません。

サンプルコードの場合、以下の分岐をカバーすれば良いことになります:

枝番 条件文 = 値
1 (condition1 || condition2) = TRUE
2 (condition1 || condition2) = FALSE
3 condition3 = TRUE
4 condition3 = FALSE

枝番1〜2と、枝番3〜4の相互の関係は考慮しなくても良いため、上記のすべての枝をカバーできる最小のテストケースの数は2です。

C2カバレッジ

この記事における C2カバレッジは以下の定義です:

  1. サンプルコードにおける condition1 〜 condition3 はC言語で言う単文の式と考えてください。この式は TRUE or FALSE の値を持ちます。これをここでは 条件式 と呼びます。
  2. C2カバレッジでは、すべての 条件式 に対して、双方の分岐をカバーしたかを計測します。

サンプルコードの場合、以下の分岐をカバーすれば良いことになります:

枝番 条件式 = 値
1 condition1 = TRUE
2 condition1 = FALSE
3 condition2 = TRUE
4 condition2 = FALSE
5 condition3 = TRUE
6 condition3 = FALSE

こちらの場合も、最小のテストケース数は2になります。
この際、条件文 の単位で値が何になっているかは考慮しなくて良いので、例えば以下の組み合わせはC2カバレッジ100%になりますが、C1/C0カバレッジは100%にならないので注意が必要です。

  • condition1 = TRUE, condition2 = FALSE, condition3 = TRUE
  • condition1 = FALSE, condition2 = TRUE, condition3 = TRUE

gcov の Branch Coverage の考え方

一方、gcov における Branch Coverage の考え方は根本的に異なっていて、そもそもソースコードの分岐を基準にしていません。

gcov が Branch Coverage と呼んでいるのは、制御フローグラフ(Control Flow Graph:CFG) における分岐の網羅です。
CFG は、大まかに言うとコンパイルの結果生成される機械語に近いレベルでの制御のフローを表したものです。

このページで使っている疑似コードの場合、CFG は下以のようなイメージになります。

gcov ではこの CFG の分岐の枝である A〜F のすべてを通ったかを Branch Coverage として計測します。

図からもわかりますが、上記のサンプルコードの場合に gcov の Branch Coverage を100%にするための最小の経路数は3で、前述のC1/C2よりも多くなっています。

このため、一般的に言って gcov の Branch Coverage は前述の C1, C2 カバレッジよりも厳しい基準になり、gcov の Branch Coverage が 100% の場合にはC1とC2のカバレッジは100%になりますが、C1カバレッジ100%やC2カバレッジ100%は gcov の Branch Coverage 100% にはならない場合が大半です。

以上から、プロジェクトの品質要件で C1 カバレッジ100%が品質要件に上がっている場合、<ins>テストの工数が増大することを厭わないのであれば</ins> gcov の Branch Coverage 100%をもって証拠とすることは可能です。

一般にC1/C2のカバレッジ計測ができるツールは高額なものが多いため、すでに導入されたツールがない場合は工数との比較で gcov を利用するかどうかを決めると良いでしょう。

参考文献

https://gcovr.com/en/stable/faq.html#why-does-c-code-have-so-many-uncovered-branches

脚注
  1. C1/C2カバレッジの定義に関する標準についてご存じの方いらっしゃいましたらコメントお願いします。 ↩︎

Discussion