googletestではじめるC++の単体テスト

今年度になって初めて単体テストなるものを使うようになったゆとりであるが,人間変われば変わるもので,コードを書いたら一緒にテストを書かないと不安を感じるようになった.それまでprintfデバッグでなんとかしてきたC/C++のコーディングもこのままではまずいと思って,巷で評判のgoogletestなるものを使うことにした.

本家のページから最新版をダウンロード(orレポジトリからチェックアウト)して

% ./configure
% make
% sudo make install

すればいいんでしょフフン,と思っていたらmake installで怒られた.どうやらv.1.5あたりからgoogletestのアーカイブファイルをその都度作成することを推奨するようになったらしい.ゆとりは想定外の挙動に大層弱いので,これで一晩費やしたことは秘密.というわけで二晩目に何とか動いたので,作業メモ.

さて,こんな感じのソースファイルを書いたとする.

#include <iostream>
#include "hoge.hpp"

int
hoge (int x)
{
  return 2 * x;
}
#ifndef __HOGE_HPP__
#define __HOGE_HPP__

int hoge (int x);

#endif

hoge関数に対する単体テストを書いてみる.

#include <gtest/gtest.h>
#include "hoge.hpp"

TEST (hogeTest, HandlesZeroInput) {
  EXPECT_EQ(0, hoge( 0 ));
}

googletestにおけるテスト用関数については僕はEXPECT_EQくらいしか知らないのでgoogletest入門ガイドなどをご参照.

これで

  • ソースファイル,ヘッダファイル
  • 単体テスト用ソースファイル

が揃った.

この先のビルド手順でハマった.実はREADMEにサンプルの確認方法が書かれている.(以降${GTEST_DIR}はgoogletestのディレクトリとする)

% cd ${GTEST_DIR}/make
% make
% ./sample1_unittest

というわけで正しいビルド手順は${GTEST_DIR}/make/Makefileに書かれているので,それを読み解くことにした.

Makefileでやっていることを読み解きながら,てしてし打ち込んでみる.(単体テスト用のmain関数を自分で書く方法もあるけれど,今回は用意されたmain関数を利用する手順)

# ソースのオブジェクトファイルを作成する
% g++ -c hoge.cpp

# 単体テストのオブジェクトファイルを作成する
% g++ -I${GTEST_DIR}/include -c hoge_test.cpp

# gtest_main のアーカイブファイルを作成する
% g++ -I${GTEST_DIR} -I${GTEST_DIR}/include -c ${GTEST_DIR}/src/gtest-all.cc
% g++ -I${GTEST_DIR} -I${GTEST_DIR}/include -c ${GTEST_DIR}/src/gtest_main.cc
% ar rv gtest_main.a gtest_main.o gtest-all.o 
ar: creating gtest_main.a
a - gtest_main.o
a - gtest-all.o

# 関数本体と単体テストとアーカイブファイルをリンクする (# 昨晩のハマりは-lpthread忘れが原因)
% g++ -I${GTEST_DIR}/include -lpthread -o hoge_test hoge.o hoge_test.o gtest_main.a

どきどきしながらテストの動作確認

% ./hoge_test 
Running main() from gtest_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from hogeTest
[ RUN      ] hogeTest.HandlesZeroInput
[       OK ] hogeTest.HandlesZeroInput (0 ms)
[----------] 1 test from hogeTest (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[  PASSED  ] 1 test.

おぉ! 緑色の文字が表示されて無事にテストが通ったことを確認.これでC++単体テストができるようになった!

自分用Makefileの書き方は以下のブログを参考に.

メモ

  • Makefileの読み方
    • $@: ターゲット
    • $^: 必須項目のリスト
    • オプションに使う変数はデフォルト値があったりするので頭の片隅に置いておくと吉
      • たとえば $(ARFLAGS)のデフォルト値はrv

追記

実はarが何をするかちゃんとわかっていなかったのだけれど,どうやらこの場合は単にオブジェクトファイルを複数まとめたもの,という扱いらしい.なのでarでまとめずに,直接gtest_main.oとgtest-all.oをリンクしてもいけるんじゃね? と思って試してみたらいけたので追記.

# この部分が
% ar rv gtest_main.a gtest_main.o gtest-all.o 
% g++ -I${GTEST_DIR}/include -lpthread -o hoge_test hoge.o hoge_test.o gtest_main.a

# これでもよい
% g++ -I${GTEST_DIR}/include -lpthread -o hoge_test hoge.o hoge_test.o gtest_main.o gtest-all.o