C++ のユニットテストを簡単にあつかえるようにしてみた。
要素としては次。
- Google Test
- https://code.google.com/p/googletest/
- 現在一番扱いやすい C++ ユニットテスト用フレームワークだと思う。
- CMake との親和性が高いのもよい。
- CMake
- http://www.cmake.org/
- ユニットテストのコンパイルを楽にするために。
- 実行と結果の要約表示は付属の CTest を使うといい感じになる。
ここでは CMake まわりの設定について説明していく。
Google Test の使い方については各自で調べてください。
サンプル
CMake の都合上ディレクトリー構造がキモになってくるのでわかりやすさのためにサンプル作ってみた。
トップで次のコマンドを打つとテストまで完了する。
mkdir build
cd build
cmake ..
make
ctest
ディレクトリー構造は次のようにしている。
project root/
cmake/ # CMake 用設定置き場
include/ # C++ 用ヘッダーファイル置き場
lib/ # ライブラリー用ディレクトリー
CMakeLists.txt # ライブラリー用設定ファイル
util/ # ライブラリー そのいち
... # その他のライブラリー
test/ # テスト用ディレクトリー
CMakeLists.txt # テスト用設定ファイル
awesome/ # テスト そのいち
... # その他の機能群用のディレクトリー
CMakeLists.txt # ビルド用設定ファイル
main.cpp # 実行ファイル用ソース
トップの CMakeLists.txt の次の部分がテストに関する設定。
# tests
if(NOT without-test)
enable_testing()
include(cmake/gtest.cmake)
add_subdirectory(test)
endif()
CMake の条件分岐
ここではテストのコンパイルをやめるかどうかを制御するために使っている。普段はテストこみでコンパイル、事情があるときだけ外す、という形。
make 時に変数 without-test が定義されているかどうかで判別している。
条件分岐については次参照。
CTest を有効化する
enable_testing() で有効になる。
その上で次のコマンドでテストの設定をする。
- add_test()
- ctest コマンド実行時にテスト対象に含める実行ファイルを指定する。
- add_executable の TARGET_FILE を指定しておいたりする。
- set_property()
- テストにラベルをつけて、特定のラベルのついたテストのみ実行ということができる。
- set_tests_properties() でもつけられるけど紛らわしいのでおすすめしない。
cmake_minimum_required(VERSION 2.8)
add_executable(awesome-test main.cpp)
target_link_libraries(awesome-test
gtest
gtest_main
pthread
util
)
add_test(
NAME awesome
COMMAND $<TARGET_FILE:awesome-test>
)
# run with: ctest -L lib
set_property(
TEST awesome
PROPERTY LABELS lib awesome
)
上記のようにしておくと次のコマンドのいずれかでこのテストが走る。
make test はラベル指定時が煩雑だね。
- ctest
- ctest -L lib
- make test
- ARGS="-L lib" make test
CMake で外部プロジェクトを取り込む
CMake には ExternalProject というモジュールが付属していて、リモートの CMake プロジェクトを取り込めるようになっている。
Google Test は ExternalProject で読み込めるようになっている。
次のような設定をファイルに切り出しておくと使い回しがきく。
cmake_minimum_required(VERSION 2.8)
# Google Test settings
include(ExternalProject)
ExternalProject_Add(
GoogleTest
URL https://googletest.googlecode.com/files/gtest-1.7.0.zip
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/lib
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property(GoogleTest source_dir)
include_directories(${source_dir}/include)
ExternalProject_Get_Property(GoogleTest binary_dir)
add_library(gtest STATIC IMPORTED)
set_property(
TARGET gtest
PROPERTY IMPORTED_LOCATION ${binary_dir}/libgtest.a
)
add_library(gtest_main STATIC IMPORTED)
set_property(
TARGET gtest_main
PROPERTY IMPORTED_LOCATION ${binary_dir}/libgtest_main.a
)
実際に使う場合は include(gtest.cmake)
という感じで。
テストを作る場合
test ディレクトリー以下に追加していく。
機能や関数ごとにサブディレクトリーを作って追加していくのがいい。
サブディレクトリーを追加した場合は test/CMakeLists.txt にそのディレクトリーを add_subdirectory() するのを忘れないように。
あと include ディレクトリーを include_directories() しているので、ヘッダーファイルのパスを include 直下からのものにする。