やったことだけ書く備忘録

MacのC++開発にCppUTestを導入してみる話

MacでC++のテスト始めるメモ


最近は業務でC++を書いてて、そういえばテストってどうやっていくのがいいのかなって思いました。
ある程度プロダクトとして形にはなったものの、満足にテストが通ってないものを提供するのは怖いですね。

で、調べて良さそうなのがCppUTestというテスティングフレームワーク。これの導入からテストの書き方と実行までをメモしておきます。

C++のテストといえばGoogle Testが有名だそうですが、なんとなく使いやすそうだったのでCppUTestを選択しました。実はあんまりシンタックスとかは変わらないみたいです。

関連エントリは結構あるんですが、やっぱりVC++が多くて、XcodeかCLIでやるのにシンプルな方法があんまりなかった。まぁこのへんはツールの問題だとは思いますが。
今回はMac OSのコマンドラインから実行するところまでです。そういえばCLIで開発してる人っているのかな?


参考:C/C++のユニットテストフレームワーク CppUTest が便利



ソースコードはGithubにありまぁす:


CppUTest unit testing and mocking framework for C/C++



CppUTestのインストール


Homebrewから入ります。とても嬉しい。




$ brew install cpputest


私は3.6がインストールされました。なお、実際に使うときにはインクルード指定とリンクの指定もしないといけないので、この場合は/usr/local/Cellar/cpputest/3.6という指定をすることになりますね。



テストを書く・実行する


上記の参考サイトの通りなんですが、一応書きます(Makefileは参考にさせてもらって一部Macで動くように変更した)。同一階層にsample.h、sample.cpp、sample_test.cpp、Makefileを配置。



sample.h



#include <string>

class Sample
{
public:
    
Sample();

    
std::string echo();
};
 


sample.cpp



#include "sample.h"

Sample::Sample() {}

std::string Sample::echo()
{
    return 
"Hello, World!";
}
 


sample_test.cpp



#include "CppUTest/CommandLineTestRunner.h"
#include "sample.h"

TEST_GROUP(SampleTestGroup) {

    
Samples;

    
TEST_SETUP() {
        
= new Sample();
    }

    
TEST_TEARDOWN() {
        
delete s;
    }
};

TEST(SampleTestGroupEchoTestSuccess) {
    
STRCMP_EQUAL("Hello, World!"s->echo().c_str());
}

TEST(SampleTestGroupEchoTestFail) {
    
STRCMP_EQUAL("Hellp, World!"s->echo().c_str());
}

int main(int argcchar** argv) {
    return 
RUN_ALL_TESTS(argcargv);
}
 


サンプルのクラスのほうはいいとして、sample_test.cppの書き方ですが、CppUTest/CommandLineTestRunner.hをincludeすると、CppUTestが提供するマクロ群が使えるようになります。
BDDとかと照らし合わせると、TEAT_GROUPマクロがdescribe、TESTマクロがitに対応しているような感じですかね。setUp/tearDownもちゃんとあって素敵です。で、Makefileでコンパイルします。



Makefile



CXX 
g++
CXXFLAGS = -std=c++11 -stdlib=libstdc++ --Wall -fprofile-arcs -ftest-coverage -I./ -I$(CPPUTEST_HOME)/include
LDFLAGS = -L./ -L$(CPPUTEST_HOME)/lib -lCppUTest -lCppUTestExt
CPPUTEST_HOME 
= /usr/local/Cellar/cpputest/3.6
TARGET 
sample_cpputest
SRCS 
sample.cpp sample_test.cpp
OBJS 
= $(SRCS:.cpp=.o)

all: $(TARGET)

$(
TARGET): $(OBJS)
    $(
CXX) -$@ $^ $(CXXFLAGS) $(LDFLAGS)

$(
OBJS): $(SRCS)
    $(
CXX) -$(CXXFLAGS) $^

%.
o: %.cpp
    
$(CXX) -$(CXXFLAGS) $<

.
PHONYclean
clean
:
    
rm -$(TARGET) $(OBJS) *.gcno *.gcov *
    
find . -name "*.gcda" xargs rm
 


今のプロジェクトはC++11使えるので、C++11のフラグをつけています。細かい設定値はまぁ見てもらうとして、-fprofile-arcsでプロファイリングを有効に、-ftest-coverageでカバレッジも取れるみたいです。
他にもメモリリークの検出なんかもできるそうで。この辺りはまだやってない。

で、ビルドして実行すると、




$ make
g++ -c -std=c++11 -stdlib=libstdc++ -g -Wall -fprofile-arcs -ftest-coverage -I./ -I/usr/local/Cellar/cpputest/3.6/include sample.cpp sample_test.cpp
g++ -o sample_cpputest sample.o sample_test.o -std=c++11 -stdlib=libstdc++ -g -Wall -fprofile-arcs -ftest-coverage -I./ -I/usr/local/Cellar/cpputest/3.6/include -L./ -L/usr/local/Cellar/cpputest/3.6/lib -lCppUTest -lCppUTestExt

$ ./sample_cpptest

sample_test.cpp:22: error: Failure in TEST(SampleTestGroup, EchoTestFail)
expected
but was
difference starts at position 4 at: < Hello, World! >
^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)


テストが実行されて、期待どおりEchoTestFailのテストケースは失敗しました。



実際は多分Xcodeで


今回はCLIでやりましたが、実際はXcodeでやると思います。その時も普通にHeader Search PathとLibrary Search Path、あとLink BinaryにCppUTestを追加すれば普通に動くと思います。
細かい機能のうちはテストケースを自動で生成してコンパイル、実行するタスクをgulpで書いてやっています(このへんはフロントエンドっぽい感じある)。



まとめ


LL言語のようにサラサラと書いてテストを動かすようなカジュアルさはないけど、これはこれで、という感じでわりと馴染む感じでした(そもそもこの辺りの経験がうすい)。
Visual Studio使ったことすらないし・・・。

まぁ、MacでもC++の開発はできるし、iOS関連だとOSの選択の余地がないので仕方ないと思います…(ググってVisual Studioのエントリばかりヒットしてつらみを感じている)。
年末の現場からは以上です。

« 前の記事 次の記事 »

0件のコメント

コメントを投稿する

 画像に表示されている文字を入力してください。