最近のC/C++のテスト環境で人気があるのはgoogletest (=Google C++ Testing Framework)だと思われる。今回はCygwinでgoogletestを使ってみる。Linuxでも同じだと思われる。
準備
- gtest-X.X.X.zipをgoogletest - Google C++ Testing Framework - Google Project Hostingからダウンロード(現時点で1.7.0)
- zipを解凍
googletestの仕組み
テストを行うべき関数が書かれている関数をfunc.ccとする。func.ccとmain.ccをコンパイルしてリンクすると、普通のアプリができる。
プログラマは、func.ccの単体テストを記述したfunc_unittest.ccを作成する。次にfunc.cc, func_unittest.cc, gtest_main.cc, gtest-all.ccをコンパイルしてリンクすると、単体テスト用のアプリができる。これを実行すると、単体テストが走り、結果が表示される。
googletestのサンプルを動かす
上で説明した、単体テスト用のアプリを作るための手続きの例が、googletestのmake/フォルダに用意されている。手順は以下の通り。
- $ cd make
- $ make
- sample1_unittest.exeが生成される
- $ ./sample1_unittest.exe
sample1_unittest.exeを実行することで単体テストが走り、結果が表示される。"[ PASSED ] 6 tests."と表示されるはず。
何が起こったのか
上記Makefileで何が起こったのかを調べてみる。makeにより実行されたのは以下の行。
g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1.cc g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1_unittest.cc g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c \ ../src/gtest-all.cc g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c \ ../src/gtest_main.cc ar rv gtest_main.a gtest-all.o gtest_main.o ar: gtest_main.a を作成しています a - gtest-all.o a - gtest_main.o g++ -isystem ../include -g -Wall -Wextra -pthread -lpthread sample1.o sample1_unittest.o gtest_main.a -o sample1_unittest
以下、一行ずつ精査していく。
g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1.cc
この行では、sample1.ccをコンパイルしてsample1.oを生成する。
sample1.ccには、整数nの階乗を返すFactorial()と、整数nが素数かどうかを判定するIsPrime()関数が実装されている。
例えばFactorial()は以下のように実装されている。
int Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; }
sample1.ccはgoogletestのことは知らない。
g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1_unittest.cc
この行では、sample1_unittest.ccをコンパイルしてsample1_unittest.oを生成する。sample1_unittest.ccはsample1.ccをテストするためのファイルである。
sample1_unittest.ccでは、まず必要なヘッダをインクルードする。
#include <limits.h> #include "sample1.h" #include "gtest/gtest.h"
次に、FactorialTest()をテストする関数が並んでいる。まずはFactorialTest()に負数を与えたときのテストである。
TEST(FactorialTest, Negative) { EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_GT(Factorial(-10), 0); }
"Negative"というのはこのテストの名前である。その下の三行がテストケースに相当する。EXPECT_EQ(1, Factorial(-5)); というテストケースは、Factorial(-5)の結果が1であることを期待している、という意味である。EXPECT_GTは、Factorial(-10)の結果が0より大きいことを期待している、という意味である。
Primer - googletest - Getting started with Google C++ Testing Framework - Google C++ Testing Framework - Google Project Hostingによると、テスト記法には他に以下のものがある。ASSERT系は致命的な失敗を意味し、失敗したら関数を抜ける。EXEPCT系の場合は、失敗しても関数を抜けない。ASSERT系でもEXPECT系でも、失敗した場合はテスト自体がFAILUREになることには違いはない。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_EQ(expected, actual); | EXPECT_EQ(expected, actual); | expected == actual |
ASSERT_NE(val1, val2); | EXPECT_NE(val1, val2); | val1 != val2 |
ASSERT_LT(val1, val2); | EXPECT_LT(val1, val2); | val1 < val2 |
ASSERT_LE(val1, val2); | EXPECT_LE(val1, val2); | val1 <= val2 |
ASSERT_GT(val1, val2); | EXPECT_GT(val1, val2); | val1 > val2 |
ASSERT_GE(val1, val2); | EXPECT_GE(val1, val2); | val1 >= val2 |
g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c ../src/gtest-all.cc
オブジェクトファイルgtest-all.oを生成する。これはgoogletestのライブラリの素になるファイルであった。
g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c ../src/gtest_main.cc
オブジェクトファイルgtest-main.oを生成する。gtest_main.ccには以下のmain関数が記述されている。
#include <stdio.h> #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { printf("Running main() from gtest_main.cc\n"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
ar rv gtest_main.a gtest-all.o gtest_main.o
gtest-all.o と gtest_main.o とから、スタティックライブラリgtest_main.aを生成する。
g++ -isystem ../include -g -Wall -Wextra -pthread -lpthread sample1.o sample1_unittest.o gtest_main.a -o sample1_unittest
オブジェクトファイルとスタティックライブラリをリンクして、実行ファイルsample1_unittestを生成する。
まとめ
この記事では、googletestに付属するサンプルのうちsample1.ccに実装された関数の単体テストを実行した。googletestには他にもsample2〜sample10までサンプルが存在する(各サンプルの簡単な説明)。そのうちこれらのサンプルについても詳細を調べてみたい。
→ 続き書きました(
googletestに付属するサンプルを読み解く - minus9d's diary)