The jonki

呼ばれて飛び出てじょじょじょじょーんき

cmakeでgoogletestできる環境を作ってみる

はじめに

googletestをcmakeで動かす必要があったのでまとめました.googletestはc++のテストフレームワークで,cmakeはコンパイラに依存しないビルド自動化のソフトです.tjunさんが既に記事を書いてくれていますが,私は生Makefileはゆとりすぎて読めないのでcmakeで焼き直しました.
GoogleTestでC++のコードをテストする - Qiita

テスト用に簡単なサンプルプロジェクトをgithubにアップしました.READMEに最低限書いてますが,それを説明します.
github.com

プロジェクト構成

今回はこのようなフォルダ構成にしてみました.src/の下にmy_mathという自作のライブラリを作ってあります.それをtest/下のテストクラスで叩いてバグがないか確認してみる,という設定です.

.
|-- CMakeLists.txt
|-- src
|   |-- CMakeLists.txt
|   |-- main.cc
|   |-- my_math.cc
|   `-- my_math.h
`-- test
    |-- CMakeLists.txt
    `-- test.cc


この中のmy_mathライブラリのsum関数はあえて間違って実装しています.

#include  "my_math.h"

double sqr(double v) {
  return (v*v);
}

double sum(double v1, double v2) {
  return v1 - v2; // Oops! bug!
}

cmakeファイル

CMakeLists.txtはフォルダ毎に用意して疎に書いておくのが良いと思っています.

ルート直下のCMakeLists.txt
ここでやっていることはadd_subdirectoryで下位フォルダのCMakeLists.txtを読み込みに行きます.またenable_testingでctestを有効にし,add_testで具体的なテストを指定しています.ctestとはcmakeについているテスト実行の支援ツールです.

cmake_minimum_required(VERSION 2.8)
project (MYTEST)

add_subdirectory(src)
add_subdirectory(test)
enable_testing()
add_test(NAME MyTest COMMAND Test)

src/のCMakeLists.txt
ここではmy_mathライブラリを作り,mainのプログラムでlibmy_math.aをリンクしています.リンク時のライブラリ名の指定の時に'lib'のプレフィックスは省略できます.またこのlibmy_math.aはテストにも利用します.

cmake_minimum_required(VERSION 2.8)
add_library(my_math STATIC my_math.cc)

add_executable(demo main.cc)
target_link_libraries(demo my_math)

test/のCMakeLists.txt
少し長いですが,難しいことはありません.googletestライブラリのインクルードディレクトリ及びライブラリディレクトリを指定し,test.ccに対してlibgtest.a,libgtest_main.a,pthreadをリンクしているだけです.pthreadはgoogletestで必要になりますので忘れないように.またGTEST_ROOTで指定しているgoogletestのインストールディレクトリは適宜読み替えてください.

cmake_minimum_required(VERSION 2.8)

# set runtime directory
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

# declare GTEST_ROOT
set(GTEST_ROOT ~/googletest/googletest/)

# Include files directory
include_directories(${GTEST_ROOT}/include/)

# Library directory
link_directories(${GTEST_ROOT}/build/)

# Generate executable file
add_executable(Test ${CMAKE_CURRENT_SOURCE_DIR}/test.cc)

# Link libraries
target_link_libraries(Test my_math gtest gtest_main pthread)
テストファイルと実行

それではテストファイルです.SqrFuncCheckとSumFuncCheckの2つのテストを用意して,sqrとsum関数をテストしてみます.sum関数の実装は間違っているので,テストは通らないはずです.

#include "../src/my_math.h"
#include <gtest/gtest.h>

namespace {
  class MyLibTest : public ::testing::Test{};

  TEST_F(MyLibTest, SqrFuncCheck) {
    EXPECT_EQ(sqr(3.0), 9.0);
    EXPECT_EQ(sqr(4.0), 16.0);
  }

  TEST_F(MyLibTest, SumFuncCheck) {
    EXPECT_EQ(sum(1.0, 2.0), 3.0);
  }
}

実行してみます.ちゃんと失敗しています.make後にbuild/test/Testを直接叩いても大丈夫です.

$ git clone https://github.com/jojonki/googletest-with-cmake-sample/
$ cd googletest-with-cmake-sample/
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make test # or ctest --verbose
$ ctest --verbose
(略)
test 1
    Start 1: MyTest

1: Test command: /path/to/googletest-with-cmake-sample/build/test/Test
1: Test timeout computed to be: 9.99988e+06
1: Running main() from gtest_main.cc
1: [==========] Running 2 tests from 1 test case.
1: [----------] Global test environment set-up.
1: [----------] 2 tests from MyLibTest
1: [ RUN      ] MyLibTest.SqrFuncCheck
1: [       OK ] MyLibTest.SqrFuncCheck (0 ms)
1: [ RUN      ] MyLibTest.SumFuncCheck
1: /path/to/googletest-with-cmake-sample/test/test.cc:13: Failure
1:       Expected: sum(1.0, 2.0)
1:       Which is: -1
1: To be equal to: 3.0
1:       Which is: 3
1: [  FAILED  ] MyLibTest.SumFuncCheck (0 ms)
1: [----------] 2 tests from MyLibTest (1 ms total)
1: 
1: [----------] Global test environment tear-down
1: [==========] 2 tests from 1 test case ran. (1 ms total)
1: [  PASSED  ] 1 test.
1: [  FAILED  ] 1 test, listed below:
1: [  FAILED  ] MyLibTest.SumFuncCheck
1: 
1:  1 FAILED TEST
1/1 Test #1: MyTest ...........................***Failed    0.00 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.01 sec

The following tests FAILED:
	  1 - MyTest (Failed)
Errors while running CTest
まとめ

cmakeでgoogletestを使ったプロジェクトを作ることができるようになりました.どんどんテストしましょう.googletestをもう少し使い込みたいところです.