Cutter+Jenkinsを使ったC++のテスト(1)

前回までにインストールしたJenkinsを使い、C++のテスト環境を整えてみます(本当は早くXcode+swift+gitの環境を整えたいけれど、準備が大事)。

swiftlife.hatenablog.jp

C++のテストツールは、内輪で評判のいい「cutter」を使ってみます。Jenkinsとの連携がどこまでできるのか不安ですが、有名どころなので多分大丈夫でしょう。

cutterのインストール

cutterのインストールも、Jenkinsのときと同じくHomebrewを使います。

% brew info cutter
cutter: stable 1.2.5, HEAD
Unit Testing Framework for C and C++
http://cutter.sourceforge.net/
Not installed
From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/cutter.rb
==> Dependencies
Build: pkg-config ✔, intltool ✘
Required: glib ✘, gettext ✘

pig-configやinittool、それにglibとgettextが必要みたいです。一気にインストールしてしまいます。

% brew install cutter
🍺  /usr/local/Cellar/intltool/0.51.0: 19 files, 224K
🍺  /usr/local/Cellar/gettext/0.19.6: 1921 files, 22M
🍺  /usr/local/Cellar/libffi/3.0.13: 14 files, 408K
🍺  /usr/local/Cellar/glib/2.46.0: 416 files, 18M
🍺  /usr/local/Cellar/cutter/1.2.5: 425 files, 7.1M, built in 67 seconds
% cutter --version
1.2.5

ちなみに公式ホームページのインストール方法の説明だとMacPortsを使ってますね。port、めっきり使わなくなってしまったな…。

ターミナルからの実行

Jenkinsに組み込むことを考える前に、cutterの使い方を簡単に確認しておきます。cutterは、cutterコマンドにテストディレクトリを指定して使います。そうすると指定ディレクトリにある「test_*.so」と名付けられた共有ライブラリを再帰的に検索し、そこに書かれたテストを実行してくれるツールです。

% cutter [オプション ...] テストディレクトリ

簡単なプログラムを作って試してみます。

// myClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
struct MyClass {
    int add(int lhs, int rhs);
    int sub(int lhs, int rhs);
};
#endif /*MYCLASS_H*/

// myClass.cpp
#include "myClass.h"
#include <iostream>

int MyClass::add(int lhs, int rhs) {
    return lhs + rhs;
}
int MyClass::sub(int lhs, int rhs) {
    return lhs * rhs; // bug!
}

sub()関数に問題がありますが、そのままにして.oファイルを作ります。

% clang++ myClass.cpp -c -o myClass.o

次にこのクラスをテストするためのテストコードを用意します。ファイルはcutterコマンドのオプション指定をわかりやすくするため、testフォルダの下に作ることにします。

% mkdir test; cd test
% cat test_MyClass.cpp
#include <cppcutter.h>
#include <myClass.h>

namespace test {
void test_add(void) {
    MyClass klass;
    cppcut_assert_equal(15, klass.add(7,8));
    cppcut_assert_equal(-5, klass.add(7,-12));
}
void test_sub(void) {
    MyClass klass;
    cppcut_assert_equal(3, klass.sub(5,2));
}
}

このときのポイントは以下のとおり。

  • C++用のテストを使うのでcppcutter.hをインクルードする
  • テストコードは何かの名前空間に入れておく(でないと実行してくれない)
  • 関数の名前はtest_ではじめる

そして、共有ライブラリとして作成します。Homebrewでcutterをインストールした場合、ヘッダファイルは/usr/local/include/cutter/、ライブラリは/usr/local/libにあるので、それぞれ-Iオプションと-Lオプションでパス指定を忘れないよう。

% clang++ -shared test_MyClass.cpp ../myClass.cpp -o test_MyClass.so -I/usr/local/include/cutter -I..  -L/usr/local/lib/ -lcutter

これですべての準備が整ったので、あとはcutterコマンドで実行するだけです。

% cutter .  # ←現在のフォルダを起点に探索
.F
===============================================================================
Failure: test::test_sub
<3 == klass.sub(5,2)>
expected: <3>
  actual: <10>
test_MyClass.cpp:12: void test::test_sub(): cppcut_assert_equal(3, klass.sub(5,2), )
===============================================================================


Finished in 0.001298 seconds (total: 0.000586 seconds)

2 test(s), 2 assertion(s), 1 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
50% passed

無事(?)に失敗しました。

参考サイト