業務効率化の道具箱(6)Google Testを使ってみよう【その2】山浦恒央の“くみこみ”な話(159)(3/3 ページ)

» 2022年11月28日 07時00分 公開
前のページへ 1|2|3       
※本記事はアフィリエイトプログラムによる収益を得ています

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;
}
リスト3 FizzBuzzプログラム

 上記は、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;
}
リスト4 ヘッダファイルをインクルード

(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();
}
リスト5 main関数

(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));
}
リスト6 テストマクロ、アサーションマクロを記述した状態

(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)。

図3 図3 lcovのカバレッジレポート[クリックで拡大]

 index.htmlをブラウザで開くと、図3の出力結果を確認できます。その中で、使用したディレクトリを選びます(図4)。ちなみに筆者はtestフォルダで作成しました。

図4 図4 カバレッジ計測結果[クリックで拡大]

 図4の右上のCoverageを確認してください。C0:100%のカバレッジが計測できていることが分かりますね。

 これで、一通りの確認が終了しました。

5.終わりに

 今回は、前回導入したGoogle Testの使い、アサーションとパス・カバレッジの測定を解説し、FizzBuzzプログラムで例を示しました。このツールでは、テストコードを記述することで、効率よく単体テストが実施できます。ぜひ、効率化の道具箱に入れ、いざとなったときに活用してください。

 ソフトウェア開発にはさまざまな業務があります。黙々と頑張ることも大事ですが、世の中のツールを活用し、効率化することも一つの選択肢としてはいかがでしょうか。

山浦先生の書籍が発売中です!

 前々シリーズ「ソフトウェア技術者のためのバグ百科事典」を大幅に加筆、修正した山浦恒央先生の書籍「ソフトウェア技術者のためのバグ検出テキスト」が日科技連出版から好評発売中です。連載でも取り上げた、「要求仕様書のバグ」「実装抜けのバグ」「テスト業務のバグ」など、バグを36種類に分類して解説しています。囲碁や将棋であれば、「相掛かり」「矢倉」「四間飛車」「藤井システム」のような戦法を網羅した内容になっています。

 前著「ソフトウェア技術者のためのバグ検出ドリル」(2019年11月刊行)も好評発売中です。実際にバグを含む要求仕様書、設計書、コーディング、デバッグ、保守を具体的に取り上げ、練習問題として31問を出題しました。同書は、囲碁や将棋における「次の一手」的な問題であり、ピンポイントの場面を取り上げ、実践力を鍛えることを目的としています。

 両書とも興味のある方は、Amazon.comや書店でチェックしてください!

【 筆者紹介 】
山浦 恒央(やまうら つねお)

東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)


1977年、日立ソフトウェアエンジニアリングに入社、2006年より、東海大学情報理工学部ソフトウェア開発工学科助教授、2007年より、同大学大学院組込み技術研究科准教授、2016年より非常勤講師。

主な著書・訳書は、「Advances in Computers」 (Academic Press社、共著)、「ピープルウエア 第2版」「ソフトウェアテスト技法」「実践的プログラムテスト入門」「デスマーチ 第2版」「ソフトウエア開発プロフェッショナル」(以上、日経BP社、共訳)、「ソフトウエア開発 55の真実と10のウソ」「初めて学ぶソフトウエアメトリクス」(以上、日経BP社、翻訳)。


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.