周囲で「プログラムのテストを綺麗にやろう」という風潮が高まっているので,次のフレームワークを試してみました.
はじめに: Cutterリファレンスマニュアル - Cutter
CにもC++にも対応しているということなので,簡単なサンプルを作りました.
まず,ヘッダファイルとソースファイル.
#ifndef __CALC_H
#define __CALC_H
#include <iostream>
using namespace std;
class Calc
{
public:
Calc();
~Calc();
int add(int a, int b);
}
#endif
#include <Calc.h>
Calc::Calc()
{
cout<<"Calc constructor"<<endl;
}
Calc::~Calc()
{
cout<<"Calc destructor"<<endl;
}
int Calc::add(int a, int b)
{
return(a+b);
}このサンプルを,共有ライブラリ化します.
> g++ -o lib/Calc.o -c lib/Calc.cc -I./lib > ar crv lib/libCalc.so lib/Calc.o a - lib/Calc.o
ライブラリを呼び出すメインルーチンを作成し,ライブラリとリンクさせて動作確認します.
#include <Calc.h>
int main()
{
Calc *calc = new Calc();
cout<<calc->add(1,2)<<endl;
delete calc;
return(0);
}> g++ -o src/main src/main.cc -Llib -lCalc -Ilib > ./src/main Calc constructor 3 Calc destructor
確かに,コンストラクタが呼ばれて,足し算して,デストラクタが呼ばれました.
ただし,いちいちメインルーチンを作って目視で動作確認をするのが大変なので,Cutter用のテストプログラムを作ります.
#include <cppcutter.h>
#include <Calc.h>
void test_Calc()
{
Calc *calc = new Calc();
cppcut_assert_equal(3, calc->add(1,2));
delete calc;
}Cutterの仕様に従って,このテストプログラムも共有ライブラリ化します.
そしてCutterを通して実行しようとしても...実行されません...
> g++ -o test/test_Calc.so test/test_Calc.cc -I/usr/local/include/cutter -Llib -lCalc -Ilib -L/usr/local/lib -lcppcutter -shared > ls test/ test_Calc.cc test_Calc.so > cutter test/ Finished in 0.000144 seconds (total: 0.000000 seconds) 0 test(s), 0 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 0% passed
無視されます.
ここで3日くらい悩みました...
結局分かったことは,CじゃなくてC++の場合は,namespaceでテストルーチンを囲むと出来ました.
#include <cppcutter.h>
#include <Calc.h>
namespace testCalc
{
void test_Calc()
{
Calc *calc = new Calc();
cppcut_assert_equal(3, calc->add(1,2));
delete calc;
}
}> g++ -o test/test_Calc.so test/test_Calc.cc -I/usr/local/include/cutter -Llib -lCalc -Ilib -L/usr/local/lib -lcppcutter -shared > cutter test/ Calc constructor Calc destructor . Finished in 0.002072 seconds (total: 0.000615 seconds) 1 test(s), 1 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 100% passed
1+2=3になったので,全てのテストにパスしたと出ました.
さらっと終わってしまうと,本当にテストされているのか心配になるのが人情です.
そこで,テストが失敗するであろう例を作ってみます.
#include <Calc.h>
Calc::Calc()
{
cout<<"Calc constructor"<<endl;
}
Calc::~Calc()
{
cout<<"Calc destructor"<<endl;
}
int Calc::add(int a, int b)
{
return(a+b+1);
}わざとバグを混入です.足し算の結果がちゃんと出るのではなく,足し算の結果に1だけさらに足された結果が出ます.
実行確認+Cutter確認してみますと...
> g++ -o lib/Calc.o -c lib/Calc.cc -I./lib > ar crv lib/libCalc.so lib/Calc.o r - lib/Calc.o > g++ -o src/main src/main.cc -Llib -lCalc -Ilib > ./src/main Calc constructor 4 Calc destructor > g++ -o test/test_Calc.so test/test_Calc.cc -I/usr/local/include/cutter -Llib -lCalc -Ilib -L/usr/local/lib -lcppcutter -shared > cutter test/ Calc constructor F 1) Failure: testCacl::test_Calc <calc->add(1,2) == 4> expected: <3> actual: <4> test/test_Calc.cc:9: void testCacl::test_Calc()(): cppcut_assert_equal(3, calc->add(1,2), ) Finished in 0.003860 seconds (total: 0.001037 seconds) 1 test(s), 0 assertion(s), 1 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 0% passed
ちゃんとエラーを検知してくれました.
「1+2=3を期待しているけど,4になってる」って言ってくれてます.