次は、例題のプログラム(FizzBuzz)を使い、パス・カバレッジを計測する方法を記述します。パス・カバレッジには、以下の種類があります。
カバレッジで最も緩い基準。ソースコードの命令語を全て実行した場合、COカバレッジを100%網羅したことになります。実行したソースコードを赤く塗った場合、全てのソースコードに色がついた状態で、最大100回繰り返すループがあっても、1回実行すればCOカバレッジは100%網羅したことになります。「自動車のテストをする場合、1回もテストしないスイッチがある自動車を市場にリリースしない」のと同様、1回も実行していないソースコードがあるプログラムを出荷することはあり得ません。
ソースコードのパスを全て実行した場合、C1カバレッジを100%網羅したことになります。If文で、else文が空の場合でも、thenとelseの両方を実行しなければなりません(C0カバレッジでは、elseを実行する必要はありません)。
ソースコードのとり得る全ての条件を網羅した場合、C2カバレッジを100%網羅したことになります。If文が2個、直列でつながっている場合、両方のthenとelseを実行しなければなりません(then1-then2、then1-else2、else1-then2、else1-else2の4通り)。
ソースコードのとり得る全ての条件の組み合わせを網羅した場合、C∞カバレッジを100%網羅したことになります。1パスを1秒で実行できても数百年かかりますので、100%網羅することは不可能ではありませんが現実的ではありません。
以降、カバレッジの基本である「C0カバレッジの100%網羅」を実施するテストコードを作成します。
今回のテスト対象は以下のリスト3です。
//テスト対象:FizzBuzz.cpp /* ・3と5で割り切れる数値の場合は1を返す ・3で割り切れる数値の場合は2を返す ・それ以外の数値の場合は3を返す */ int FizzBuzz(int input){ int ret = 0; if ((input % 3) == 0 && (input % 5) == 0) { ret = 1; } else if ((input % 3) == 0){ ret = 2; } else { ret = 3; } return ret; }
上記は、FizzBuzzプログラムを関数化したものです。引数に数値を入れ、下記を判定して出力値を返します。
説明の便宜上、戻り値に1〜3を返すプログラムとしています(少し戸惑うかもしれません)。
ここでは、テストコードを作成します。C0カバレッジは、ソースコードの全ての命令語を実行できればOKです。このプログラムで「C0:100%」とするには、下記の条件を満たすテストコードを1件ずつ作成すればOKです。
それでは、テストコードを記述しましょう。
話を簡単にするため、今回は、FizzBuzz.cppにテストコードを入れます。まずは、Google Testのヘッダファイルをインクルードします(リスト4)。
#include <gtest/gtest.h> int FizzBuzz(int input){ int ret = 0; if ((input % 3) == 0 && (input % 5) == 0) { ret = 1; } else if ((input % 3) == 0){ ret = 2; } else { ret = 3; } return ret; }
main関数を作成します(リスト5)。
#include <gtest/gtest.h> int FizzBuzz(int input){ int ret = 0; if ((input % 3) == 0 && (input % 5) == 0) { ret = 1; } else if ((input % 3) == 0){ ret = 2; } else { ret = 3; } return ret; } //main処理、初期化、テスト実行を記述 int main(int argc, char **argv) { int res = 0; //Google Testの初期化 ::testing::InitGoogleTest(&argc, argv); //全テスト実行 return RUN_ALL_TESTS(); }
FizzBuzzプログラムをテストするための、テストマクロ、アサーションマクロを記述します(リスト6)。
#include <gtest/gtest.h> int FizzBuzz(int input){ int ret = 0; if ((input % 3) == 0 && (input % 5) == 0) { ret = 1; } else if ((input % 3) == 0){ ret = 2; } else { ret = 3; } return ret; } //main処理、初期化、テスト実行を記述 int main(int argc, char **argv) { //Google Testの初期化 ::testing::InitGoogleTest(&argc, argv); //全テスト実行 return RUN_ALL_TESTS(); } //テストマクロ、アサーションマクロを追加する。 TEST(FizzBuzzTest, Value){ //3と5で割り切れる数値15の場合は1を返す EXPECT_EQ(1, FizzBuzz(15)); //3で割り切れる数値6の場合は2を返す EXPECT_EQ(2, FizzBuzz(6)); //それ以外の数値は3を返す EXPECT_EQ(3, FizzBuzz(8)); }
コンパイルとテストを実行します。コマンドは下記の通りです。
g++ FizzBuzz.cpp -lgtest -lgtest_main -lpthread ./a.out
テスト実行すると、下記のメッセージを表示します。
[==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from FizzBuzzTest [ RUN ] FizzBuzzTest.Value [ OK ] FizzBuzzTest.Value (0 ms) [----------] 1 test from FizzBuzzTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test suite ran. (0 ms total) [ PASSED ] 1 test.
メッセージには、「PASSED」と書いてあるため、テストが成功したことが分かります。
最後は、gcov/lcovを使用してカバレッジを計測します。
g++ -fprofile-arcs -ftest-coverage FizzBuzz.cpp -lgtest -lgtest_main -lpthread ./a.out lcov -d . -c -o LcovData.info lcov --remove LcovData.info '/usr/*' -o ActualLcovData.info genhtml ActualLcovData.info -o ./info
上記のコマンドは、FizzBuzz.cppをコンパイルし、実行したパス・カバレッジを計測するものです。計測したデータは、infoフォルダ内のindex.htmlから確認できます(図3)。
index.htmlをブラウザで開くと、図3の出力結果を確認できます。その中で、使用したディレクトリを選びます(図4)。ちなみに筆者はtestフォルダで作成しました。
図4の右上のCoverageを確認してください。C0:100%のカバレッジが計測できていることが分かりますね。
これで、一通りの確認が終了しました。
今回は、前回導入したGoogle Testの使い、アサーションとパス・カバレッジの測定を解説し、FizzBuzzプログラムで例を示しました。このツールでは、テストコードを記述することで、効率よく単体テストが実施できます。ぜひ、効率化の道具箱に入れ、いざとなったときに活用してください。
ソフトウェア開発にはさまざまな業務があります。黙々と頑張ることも大事ですが、世の中のツールを活用し、効率化することも一つの選択肢としてはいかがでしょうか。
前々シリーズ「ソフトウェア技術者のためのバグ百科事典」を大幅に加筆、修正した山浦恒央先生の書籍「ソフトウェア技術者のためのバグ検出テキスト」が日科技連出版から好評発売中です。連載でも取り上げた、「要求仕様書のバグ」「実装抜けのバグ」「テスト業務のバグ」など、バグを36種類に分類して解説しています。囲碁や将棋であれば、「相掛かり」「矢倉」「四間飛車」「藤井システム」のような戦法を網羅した内容になっています。
前著「ソフトウェア技術者のためのバグ検出ドリル」(2019年11月刊行)も好評発売中です。実際にバグを含む要求仕様書、設計書、コーディング、デバッグ、保守を具体的に取り上げ、練習問題として31問を出題しました。同書は、囲碁や将棋における「次の一手」的な問題であり、ピンポイントの場面を取り上げ、実践力を鍛えることを目的としています。
両書とも興味のある方は、Amazon.comや書店でチェックしてください!
東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)
Copyright © ITmedia, Inc. All Rights Reserved.