業務効率化の道具箱(6)Google Testを使ってみよう【その2】:山浦恒央の“くみこみ”な話(159)(3/3 ページ)
ソフトウェア開発にとどまらない、PCを使う全ての人が対象となるシリーズ「業務効率化の道具箱」。第6回は、前回導入した「Google Test」の使い方と、「アサーション」「パス・カバレッジ」によるテストの方法を紹介する。
4.2 パス・カバレッジの計測
次は、例題のプログラム(FizzBuzz)を使い、パス・カバレッジを計測する方法を記述します。パス・カバレッジには、以下の種類があります。
COカバレッジ(命令語網羅)
カバレッジで最も緩い基準。ソースコードの命令語を全て実行した場合、COカバレッジを100%網羅したことになります。実行したソースコードを赤く塗った場合、全てのソースコードに色がついた状態で、最大100回繰り返すループがあっても、1回実行すればCOカバレッジは100%網羅したことになります。「自動車のテストをする場合、1回もテストしないスイッチがある自動車を市場にリリースしない」のと同様、1回も実行していないソースコードがあるプログラムを出荷することはあり得ません。
C1カバレッジ(パス網羅)
ソースコードのパスを全て実行した場合、C1カバレッジを100%網羅したことになります。If文で、else文が空の場合でも、thenとelseの両方を実行しなければなりません(C0カバレッジでは、elseを実行する必要はありません)。
C2カバレッジ(条件網羅)
ソースコードのとり得る全ての条件を網羅した場合、C2カバレッジを100%網羅したことになります。If文が2個、直列でつながっている場合、両方のthenとelseを実行しなければなりません(then1-then2、then1-else2、else1-then2、else1-else2の4通り)。
C∞カバレッジ(完全網羅)
ソースコードのとり得る全ての条件の組み合わせを網羅した場合、C∞カバレッジを100%網羅したことになります。1パスを1秒で実行できても数百年かかりますので、100%網羅することは不可能ではありませんが現実的ではありません。
以降、カバレッジの基本である「C0カバレッジの100%網羅」を実施するテストコードを作成します。
4.2.1 例題:FizzBuzzプログラム
今回のテスト対象は以下のリスト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プログラムを関数化したものです。引数に数値を入れ、下記を判定して出力値を返します。
- 3と5で割り切れる場合は1を返す
- 3で割り切れる場合は2を返す
- それ以外は3を返す
説明の便宜上、戻り値に1〜3を返すプログラムとしています(少し戸惑うかもしれません)。
4.2.2 テストコード作成例
ここでは、テストコードを作成します。C0カバレッジは、ソースコードの全ての命令語を実行できればOKです。このプログラムで「C0:100%」とするには、下記の条件を満たすテストコードを1件ずつ作成すればOKです。
- 3と5で割り切れる場合は1を返す(例:15)
- 3で割り切れる場合は2を返す(例:6)
- それ以外は割り切れる場合は3を返す(例:5)
それでは、テストコードを記述しましょう。
(1)ステップ1:ヘッダファイルをインクルードする
話を簡単にするため、今回は、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; }
(2)ステップ2:main関数の作成
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(); }
(3)ステップ3:テストコードを記述する
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)); }
(4)ステップ4:コンパイルとテスト実行
コンパイルとテストを実行します。コマンドは下記の通りです。
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」と書いてあるため、テストが成功したことが分かります。
(5)ステップ5:カバレッジの計測
最後は、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%のカバレッジが計測できていることが分かりますね。
これで、一通りの確認が終了しました。
5.終わりに
今回は、前回導入したGoogle Testの使い、アサーションとパス・カバレッジの測定を解説し、FizzBuzzプログラムで例を示しました。このツールでは、テストコードを記述することで、効率よく単体テストが実施できます。ぜひ、効率化の道具箱に入れ、いざとなったときに活用してください。
ソフトウェア開発にはさまざまな業務があります。黙々と頑張ることも大事ですが、世の中のツールを活用し、効率化することも一つの選択肢としてはいかがでしょうか。
山浦先生の書籍が発売中です!
前々シリーズ「ソフトウェア技術者のためのバグ百科事典」を大幅に加筆、修正した山浦恒央先生の書籍「ソフトウェア技術者のためのバグ検出テキスト」が日科技連出版から好評発売中です。連載でも取り上げた、「要求仕様書のバグ」「実装抜けのバグ」「テスト業務のバグ」など、バグを36種類に分類して解説しています。囲碁や将棋であれば、「相掛かり」「矢倉」「四間飛車」「藤井システム」のような戦法を網羅した内容になっています。
前著「ソフトウェア技術者のためのバグ検出ドリル」(2019年11月刊行)も好評発売中です。実際にバグを含む要求仕様書、設計書、コーディング、デバッグ、保守を具体的に取り上げ、練習問題として31問を出題しました。同書は、囲碁や将棋における「次の一手」的な問題であり、ピンポイントの場面を取り上げ、実践力を鍛えることを目的としています。
両書とも興味のある方は、Amazon.comや書店でチェックしてください!
東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- ≫連載「山浦恒央の“くみこみ”な話」バックナンバー
- 業務効率化の道具箱(5)Google Testを使ってみよう【その1】
ソフトウェア開発にとどまらない、PCを使う全ての人が対象となるシリーズ「業務効率化の道具箱」。第5回は、単体テストで役立つフリーのツールである「Google Test」と「gcov/lcov」を紹介する。 - 業務効率化の道具箱(4)VirtualBoxでUbuntu環境を構築しよう
ソフトウェア開発にとどまらない、PCを使う全ての人が対象となるシリーズ「業務効率化の道具箱」。第4回は、仮想化ソフトウェアの「VirtualBox」を使って、Windows PC上にLinuxのUbuntuの環境を構築する方法を紹介する。 - 業務効率化の道具箱(3)続・ショートカットキー活用、「技術の複利効果」で作業効率が上がりミスも減る
ソフトウェア開発にとどまらない、PCを使う全ての人が対象となるシリーズ「業務効率化の道具箱」。第3回は、第2回に続きショートカットキーを紹介する。塵も積もれば山となる方式で得られる「技術の複利効果」により、急激に作業効率が上がり、同時にミスも減らせるはずだ。 - 業務効率化の道具箱(2)ショートカットキーも積もれば山となる
ソフトウェア開発にとどまらない、PCを使う全ての人が対象となるシリーズ「業務効率化の道具箱」。第2回は“塵も積もれば山になる”の効果を実感できるショートカットキーを紹介する。 - 業務効率化の道具箱(1)ソフト開発だけじゃないPCの業務効率を高める5つの道筋
今回から新シリーズ「業務効率化の道具箱」がスタート。ソフトウェア開発にとどまらない、PCを使う全ての人が対象となる。シリーズ第1回はイントロダクション編として、業務を効率化する方法にどのようなものがあるのかを提示する。