ctestの導入
ctestはcmakeに付随するテスト実行支援ツールである。 Boost TestやCppUnitとは異なり、あくまで実行を支援するツールである。 公式のページを見ると、ダッシュボードを導入しないといけないような印象を受けるが、 cmake管理化のプロジェクトであれば単独で使用できる。
何ができるか?
あなたがcmake管理化のプロジェクトを開発中、 テストを書く必要があるとする。 テストを書く事の重要性は耳にタコができるほど聴いたが、面倒な事は面倒だ。
ともあれ、mylibraryの機能Func1のテストコードtestFunc1.cppを書いたとしよう。 残念ながら、テストコードは自分でかかなければならない。 しかし、テストコードのビルドと実行は手伝う事ができる。 もしあなたが以下に説明する設定を施している場合、 あなたは単にテストコードtestFunc1.cppを含むディレクトリの CMakeLists.txtに以下の一行を追加すればいい。
mytest(Func1 S testFunc1.cpp mylibrary)
よりよいテストのためには次の行さらに前に追加するべきだろう:
set(CMAKE_BUILD_TYPE Debug)
これであなたはそのディレクトリで
make
とすれば、このコードをTEST_Func1_S
にコンパイルする事ができ、
make test
で実行する事ができる。 テストした結果は
Test project /path/to/mylibrary/test Start 1: TEST_Func1_S 1/1 Test #1: TEST_Func1_S ..................... Passed 0.02 sec 100% tests passed, 0 tsets failed out of 1 Total Test time (real) = 0.02 sec
のように表示される。 もちろん実行ファイルをそのままターミナルから実行する事も可能である。
これは現在のディレクトリ以下にあるテストを再帰的に実行するので、 プロジェクトの一番上で実行すれば全てのテストが実行される。 実行ファイルが異常終了した場合にはテストが失敗したと見做され、 まとめて表示される。
これによりコードを変更した際の再テストが
cd $PROJECT_HOME make test
とするだけでよくなる。
使い方
この記事では読者はcmakeの基本的な使い方(add_executable
くらい)を知っているとする。
まず先に私のCMakeLists.txtの抜粋を示す。
enable_testing() add_custom_target(build_test) add_custom_target(short_test COMMAND "ctest" "-R" "TEST_.*_S") add_custom_target(long_test COMMAND "ctest" "-V" "-R" "TEST_.*_L" "2>&1" ">" "long.log" "&") add_dependencies(short_test build_test) macro(mytest name type src libs) set(test_name TEST_${name}_${type}) add_executable(${test_name} ${src}) target_link_libraries(${test_name} ${libs}) add_test(${test_name} ${CMAKE_CURRENT_BINARY_DIR}/${test_name}) add_dependencies(build_test ${test_name}) unset(test_name) endmacro(mytest)
やっている事は以下の4つ:
- ctestの有効化
enable_testing()
- targetの追加
build_test
,short_test
,long_test
- 依存関係の追加 (
short_test
depends onbuild_test
) - mytestマクロの定義
ctestの有効化
enable_testing()
これを行なってcmakeを実行すると各ディレクトリにTestingディレクトリが作成される。 ctestを使用するには必須である。
targetの追加
cmakeではshellスクリプトを実行するターゲットを作成する事ができる。
add_custom_target(short_test COMMAND "ctest" "-R" "TEST_.*_S")
によって
make short_test
は依存する物(build_test
)をmakeした後、
ctest -R TEST_.*_S
を実行する。
-R
は名前が正規表現に一致するテストをすべて実行する。
実行ファイル名にS
が付いているのはこのためである。
というのも上述のコードは私の数値計算のコードなので、
一秒以内に終るもの(Sort
)もあれば、数十分かかる物(Long
)もある。
依存関係の追加
make short_test
とした際にbuild_test
がコンパイルされるようにしたのが、
add_dependencies(short_test build_test)
この行である。
さらにbuild_test
が全てのテストに依存するようにしたのが
マクロ中の
add_dependencies(build_test ${test_name})
この行である。 つまり結局
make short_test
とすれば全てのテストがコンパイルされ、実行されるのである。
マクロの定義
macro(mytest name type src libs) set(test_name TEST_${name}_${type}) add_executable(${test_name} ${src}) target_link_libraries(${test_name} ${libs}) add_test(${test_name} ${CMAKE_CURRENT_BINARY_DIR}/${test_name}) add_dependencies(build_test ${test_name}) unset(test_name) endmacro(mytest)
さていよいよマクロの定義である。
macro
は最初の引数にマクロの名前を、
以降の引数にマクロの引数を取る。
set
でテスト名を生成し、
add_executable
で実行ファイルを生成する。
肝心なのがadd_test
で、これがテストを定義している。
第一引数がテストの名前、第二引数がテストの実行ファイルである。
この際実行ファイルのパスに注意する。また追加で引数も追加できる。
上述の通りこれをbuild_test
の依存関係に追加する事で、
make short_test
で一気にmakeできる。
何故複雑な依存関係を構築したか?
ここまでで読者は不思議に思ったに違いない: 依存関係を設定しなくても全てのテストがmakeされるのではないかと。 その通りである。 しかし、ある設定をしている場合、そうはならない。
add_subdirectory(test EXCLUDE_FROM_ALL)
がその正体である。
これはtestディレクトリ以下を追加するが、
make
ではtest以下のexecutableはmake
しない、という指示である。
これにより不要なビルドを避ける事で、
ビルド時間を削減するという恩恵が得られる。
上記の設定はこの環境下で行なったための回避策である。