読者です 読者をやめる 読者になる 読者になる

googletestを使いこなす

C++

このエントリーをはてなブックマークに追加

最近のC/C++のテスト環境で人気があるのはgoogletest (=Google C++ Testing Framework)だと思われる。今回はCygwinでgoogletestを使ってみる。Linuxでも同じだと思われる。

準備

googletestの仕組み

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