2024年12月20日
カバレッジ測定 – Google Testのカバレッジ計測を試してみた #7
Google Test
今回は、g++と関連するコマンドを使用してカバレッジを確認してみます。
使用するのは、前回と同じGoogle Mockを使用したC言語プログラムのテスト環境です。
カバレッジのおさらい
ソフトウェアをテストする際には、対象のプログラムがどれくらい動作したかを確認することが一般的です。動作の程度を示すカバレッジには、実際に動作した行の割合を確認する方法やif文等の分岐条件の動作割合を確認するなど、いくつかの測定方法があります。
・C0:ステートメントカバレッジ(Statement Coverage)
プログラム中の命令文がどの程度動作したかを網羅率で表します。
・C1:ブランチカバレッジ(Branch Coverage)
プログラム中の条件文(ifやswitchなど)の処理分岐条件がどの程度動作したかを網羅率で表します。
・C2:コンディションカバレッジ(Condition Coverage)
プログラム中の条件式がどの程度動作したかを網羅率で表します。
・MC/DC:Modified Condition/Decision Coverage
条件文に書かれた複合条件に対してどの程度動作したかを網羅率で表します。
C2カバレッジはテストデータが膨大になることもあり、多くの場合、C0・C1・MC/DCによる評価が行われます。必要なテストデータの量の多さは MC/DC > C1 > C0 であり、MC/DC が最も中身の濃いテストであると言えます。
この他にも閾値の話など、テストに関わるテーマはいろいろあるのですが、今回はカバレッジ測定を試すので、C0・C1・MC/DCごとのカバレッジを100%にするために必要なテストデータについて、少しだけ触れておきます。
if ( ( a && b ) || c )
x = y;
この条件文では、例えば 変数cが0以外の値であれば、2つの行が動作するので、C0カバレッジは100%になります。しかし、C1カバレッジは50%です。
C1カバレッジを100%にするには、2行目を通らないテストデータも必要になります。さらに、MC/DCのカバレッジでは、たとえば以下の4つのテストデータを揃えてようやく100%になります。
・①と②の組み合わせでは、b・c の値が同じで a だけが異なり、式全体が真偽に分かれる
・①と③の組み合わせでは、a・c の値が同じで b だけが異なり、式全体が真偽に分かれる
・③と④の組み合わせでは、a・b の値が同じで c だけが異なり、式全体が真偽に分かれる
g++とlcovによるカバレッジ確認
g++ と lcov コマンドを使用すると、カバレッジを測定することができます。前回使用したMockを使用するC言語プログラムを使って、ブランチカバレッジを確認してみます。
まず、コンパイル時に2つのオプションを指定します。
ファイル名は、AirConditionerController_test.cpp です。
g++ -fprofile-arcs -ftest-coverage AirConditionerController_test.cpp
-lgtest -lgtest_main -lgmock -lpthread
・-fprofile-arcs オプション
コンパイル時に .gcno ファイルを生成します。.gcnoファイルには関数の制御フローグラフに関する情報が保存されています。
・-ftest-coverage オプション
コードにインストルメンテーションが追加されます(フックコードを挿入します)。これにより、プログラムのどの部分が動作したかを測定できるようになります。
これらのオプションを使用して生成したオブジェクトを実行すると、カバレッジ情報が保存された .gcda ファイルが作られます。
このファイルを使ってカバレッジの集計を行いますが、その前にホームディレクトリに置いた .lcovrc ファイル内に lcov_branch_coverage=1 を設定しておきます。これは、ブランチカバレッジを測定するための設定です。
カバレッジ集計コマンドはこちらです。
lcov -d . -c -o lcov.info
-dオプションは、.gcdaファイルのあるディレクトリを指定し、-cオプションはカバレッジデータのキャプチャを指定しています。
このコマンドで生成されたカバレッジ集計ファイル(lcov.info)にはライブラリの情報も含まれるので、不要なカバレッジ情報を削除して、別のカバレッジ集計ファイルを作ります。以下のコマンドです(/usr/の下にあるファイルのカバレッジ情報を削除しています)。
lcov --remove lcov.info '/usr/*' -o CoreCoverage.info
必要な情報だけを絞り込んだカバレッジ集計ファイルは、CoreCoverage.infoです。
最後に、この集計ファイルからHTML形式のレポートを作成する以下のコマンドを使用します。
genhtml CoreCoverage.info -o ./Report
このコマンドにより、カレントディレクトリ直下の Reportディレクトリ内にレポートが生成されます。
レポートはHTML形式なので、ブラウザで確認できます。
見えている2つのファイルは、テスト対象のソースプログラムとテストドライバーです。
テストドライバーのブランチカバレッジは100%に達していませんが、テスト対象の関数は100%です。
テスト対象関数を詳しく見てみます。
薄青色の着色は実行された行を示しています。
Line data 列にある数字はその行が何回実行されたかを示します。
Branch data 列にある[+ +]は、左の+が真条件の動作、右の+は偽条件の動作を示します。この例の場合はどちらも+なので、ブランチカバレッジ(Branches)が100%ですが、どちらかの条件だけが動作した場合には片方が+ではなく-表示となり、100%にはなりません。もし条件式が複雑になると、この+-の表示数が増えます。
たとえば、ブランチカバレッジが35.5%だったドライバーのカバレッジはこんな感じです。
おそらくGoogleTestのマクロの中に複雑な条件式が書かれていて、多くの真偽条件が動作していない状況なのでしょう。
g++とlcovによるカバレッジ測定ではMC/DCカバレッジの測定はできませんが、ステートメント(lcovの表示ではLinesとなっている)とブランチのカバレッジは確認することができます。
ただし、lcovのブランチカバレッジはC1とは異なり、それについては次回お話しします。
なお、MC/DCの測定については、GAIOのテストツール
QTE(Quality Town for Embedded grade)を使用すると可能になります。
Google Test資産を活かした車載品質テストの効率化を実現
「QTE(Quality Town for Embedded grade)」
「QTE」は、ユーザ環境で作成したGoogleTest資産を活用し、機能安全(ISO 26262)で求められるマイコンターゲットオブジェクト実行とカバレッジ計測が可能です。また、テストエビデンス及びレポートを自動出力し、テストエビデンスの作成も効率化します。
筆者紹介
浅野 昌尚(あさの まさなお)
ガイオ・テクノロジー株式会社
開発1部 QTXグループ
1980年代から30年以上にわたり汎用構造のCコンパイラ開発に従事し、その間に8ビットマイコンからRISC・VLIW・画像処理プロセッサまで、さまざまなCPU向けのクロスCコンパイラを開発。