CUnit 導入ガイド
CUnit 導入ガイド
ダウンロードとインストール
CUnitは http://sourceforge.net/projects/cunit/
からダウンロードできます。 2003.06時点での最新版は1.1-0です。
zipもしくはtar+gzipで圧縮されているので、 適当なディレクトリに展開してください。
以下の説明はWindows/Visual C++ v6.0 環境で、
CUnitのルート・ディレクトリを<CUNIT>と表記します。
ライブラリのビルド
CUnitはツール/ユーティリティの類ではありません。
テスト対象およびテストコードと一緒にリンクして実行モジュールを生成する’ライブラリ’です。
CUnitは様々なOS/処理系に対応しており、
その使用に先だってライブラリをビルドしなければなりません。
Visual Studio IDE から
プロジェクト:<CUNIT>\CUnit.dsw をオープンし、 Release/Debug
いずれかの設定でビルドします。
デフォルトではシングルスレッド版です。必要に応じてプロジェクト設定を変更してください。<CUNIT>\CUnitにライブラリ(CUnit.lib)が生成されます。
Release/Debugのいずれも同じ名前で生成されるので、これも必要に応じてプロジェクト設定を変更してください。
注意! CUnit-1.1-0にはマクロのバグがあります。
<CUNIT>\CUnit\Headers\CUnit.h に定義されたマクロ:
- ASSERT_PTR_EQUAL
- ASSERT_PTR_NOT_EQUAL
- ASSERT_PTR_NULL
- ASSERT_PTR_NOT_NULL
を、以下のように修正(下線部)してください。
- CUnit.h 修正個所
-
#define ASSERT_PTR_EQUAL(actual, expected) ASSERT(((void*)(actual) == (void*)(expected))) #define ASSERT_PTR_NOT_EQUAL(actual, expected) ASSERT(((void*)(actual) != (void*)(expected))) #define ASSERT_PTR_NULL(value) ASSERT((NULL == (void*)(value))) #define ASSERT_PTR_NOT_NULL(value) ASSERT((NULL != (void*)(value)))
テストコードの雛型
テストコードの雛型を示します。 この雛型は様々なテストに応じて書き換えて利用してください。
- XXXTest.c
-
/* * Test-group 'XXX' */ #include <TestDB.h> int XXX_init(void) { /* * テスト・グループの初期化 */ return 0; } int XXX_term(void) { /* * テスト・グループの後始末 */ return 0; } /* * テスト */ void XXX_test_01(void) { ASSERT(0 == 1); } void XXX_test_02(void) { ASSERT_TRUE(0 == 1); } void XXX_test_03(void) { ASSERT_FALSE(0 == 0); } void XXX_test_04(void) { ASSERT_EQUAL(1,2); } void XXX_test_05(void) { ASSERT_NOT_EQUAL(1,1); } void XXX_test_06(void) { int i, j; ASSERT_PTR_EQUAL(&i,&j); } void XXX_test_07(void) { int i = 0; ASSERT_PTR_NOT_EQUAL(&i,&i); } void XXX_test_08(void) { int i = 0; ASSERT_PTR_NULL(&i); } void XXX_test_09(void) { int* p = NULL; ASSERT_PTR_NOT_NULL(p); } void XXX_test_10(void) { char* x = "x"; char* y = "y"; ASSERT_STRING_EQUAL(x,y); } void XXX_test_11(void) { char* x = "x"; char* y = "x"; ASSERT_STRING_NOT_EQUAL(x,y); } void XXX_test_12(void) { char* x = "abcde"; char* y = "abcyz"; ASSERT_NSTRING_EQUAL(x,y,4); } void XXX_test_13(void) { char* x = "abcde"; char* y = "abcyz"; ASSERT_NSTRING_NOT_EQUAL(x,y,3); } void XXX_test_14(void) { double x = 1.2; double y = 1.5; ASSERT_DOUBLE_EQUAL(x,y,0.2); } void XXX_test_15(void) { double x = 1.2; double y = 1.5; ASSERT_DOUBLE_NOT_EQUAL(x,y,0.4); } /* * テスト・グループの登録 */ void XXX_register() { TestGroup* pGroup = NULL; TestCase* pTest = NULL; pGroup = add_test_group("XXX", XXX_init, XXX_term); pTest = add_test_case(pGroup, "test_01", XXX_test_01); pTest = add_test_case(pGroup, "test_02", XXX_test_02); pTest = add_test_case(pGroup, "test_03", XXX_test_03); pTest = add_test_case(pGroup, "test_04", XXX_test_04); pTest = add_test_case(pGroup, "test_05", XXX_test_05); pTest = add_test_case(pGroup, "test_06", XXX_test_06); pTest = add_test_case(pGroup, "test_07", XXX_test_07); pTest = add_test_case(pGroup, "test_08", XXX_test_08); pTest = add_test_case(pGroup, "test_09", XXX_test_09); pTest = add_test_case(pGroup, "test_10", XXX_test_10); pTest = add_test_case(pGroup, "test_11", XXX_test_11); pTest = add_test_case(pGroup, "test_12", XXX_test_12); pTest = add_test_case(pGroup, "test_13", XXX_test_13); pTest = add_test_case(pGroup, "test_14", XXX_test_14); pTest = add_test_case(pGroup, "test_15", XXX_test_15); }
- ファイル名
慣習的に、テスト対象であるモジュール名の末尾に’Test’を付加します。
たとえば、’Counter’のテストコードは’CounterTest.c’のように。 - インクルード
必要なインクルードをここに記述します。 - テストクラス
テスト・グループはテスト対象に対するテスト・ケースの集合体で、
ファイル名と同じクラス名とするのが望ましいでしょう。 - 初期化/後始末
グループ毎の初期化と後始末は、いずれも引数なし/戻り値 int の関数です。
初期化/後始末に成功したら0を返してください。 - テスト・ケース
テスト・ケースは引数/戻り値を持たない関数で、テスト項目毎に用意します。 - テスト・グループ登録
テスト・グループの登録は add_test_group で行ないます。引数はそれぞれ、名前,
初期化関数, 後始末関数 です。 add_test_group
はグループのポインタを返します。これを add_test_case
の引数として、グループにテストを登録します。 引数は、グループのポインタ, 名前, テスト関数 です。
アサート・マクロ
各テスト・ケースの中では、テスト対象が正常に機能しているかを検証するコードを記述します。
以下のアサート・マクロが用意されています。
各アサート・マクロはそれぞれ特定の条件を満たさないとき、
テスト失敗(failre)とみなしてそれ以降の処理をせずにテスト・ケースから脱出し、
次のテスト・ケースに移ります。
ASSERT( condition );
conditionが偽(0)であったとき、失敗します。ASSERT_TRUE( condition
);
conditionが偽であったとき、失敗します。ASSERT_FALSE( condition
);
conditionが真(!=0)であったとき、失敗します。ASSERT_EQUAL( expected,
actual );
得られた結果actualが期待する値expectedでなかったとき、すなわちexpected
!= actualのときに失敗します。ASSERT_NOT_EQUAL( expected,
actual );
得られた結果actualが期待する値expectedであったとき、すなわちexpected
== actualのときに失敗します。ASSERT_PTR_EQUAL( expected,
actual );
得られた結果actualが期待するポインタ値expectedでなかったとき、すなわちexpected
!= actualのときに失敗します。ASSERT_PTR_NOT_EQUAL( expected,
actual );
得られた結果actualが期待するポインタ値expectedであったとき、すなわちexpected
== actualのときに失敗します。ASSERT_PTR_NULL( actual
);
得られた結果actualがNULLポインタでなかったとき、失敗します。ASSERT_PTR_NOT_NULL( actual
);
得られた結果actualがNULLポインタであったとき、失敗します。ASSERT_STRING_EQUAL( expected,
actual );
得られた結果actualが期待する文字列expectedでなかったとき、
すなわちstrcmp(expected,actual) != 0
のときに失敗します。ASSERT_STRING_NOT_EQUAL(
expected, actual );
得られた結果actualが期待する文字列expectedと一致したとき、
すなわちstrcmp(expected,actual) == 0
のときに失敗します。ASSERT_NSTRING_EQUAL( expected,
actual, count );
得られた結果actualと期待する文字列expectedのcountが一致しなかったとき、すなわちstrncmp(expected,actual, count)
!= 0 のときに失敗します。ASSERT_NSTRING_NOT_EQUAL(
expected, actual, count
);
得られた結果actualと期待する文字列expectedのcountが一致したとき、すなわちstrncmp(expected,actual, count)
== 0 のときに失敗します。ASSERT_DOUBLE_EQUAL( expected,
actual, delta );
得られた結果actualと期待する値expectedとの差がdeltaより大きいとき、失敗します。ASSERT_DOUBLE_NOT_EQUAL(
expected, actual, delta
);
得られた結果actualと期待する値expectedとの差がdeltaより小さいとき、失敗します。
メイン・ルーチン
以上のようにして作られたいくつかのテストグループ登録関数をmainで呼び出すことで、そのテストグループがテストの対象となります。
できあがった実行モジュールはコンソール・アプリケーションとなります。
メイン・ルーチンの雛型と、実行結果を示します(下線部はユーザ入力
- メイン・ルーチン
-
#include <Console.h> int main() { void XXX_register(); initialize_registry(); XXX_register(); console_run_tests(); cleanup_registry(); return 0; }
- 実行結果
-
CUnit : A Unit testing framework for C. http://cunit.sourceforge.net/ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| (R)un all, (S)elect group, (L)ist groups, Show (F)ailures, (Q)uit Enter Command : r Running Group : XXX Running test : test_01 Running test : test_02 Running test : test_03 Running test : test_04 Running test : test_05 Running test : test_06 Running test : test_07 Running test : test_08 Running test : test_09 Running test : test_10 Running test : test_11 Running test : test_12 Running test : test_13 Running test : test_14 Running test : test_15 --Completed 1 Groups, 15 Test run, 0 succeded and 15 failed. ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| (R)un all, (S)elect group, (L)ist groups, Show (F)ailures, (Q)uit Enter Command : f ============================= Test Case Failure List ========================= 1> XXXTest.c:25 : (XXX : test_01) : 0 == 1 2> XXXTest.c:29 : (XXX : test_02) : ((0 == 1) != FALSE) 3> XXXTest.c:33 : (XXX : test_03) : ((0 == 0) == FALSE) 4> XXXTest.c:37 : (XXX : test_04) : ((1) == (2)) 5> XXXTest.c:41 : (XXX : test_05) : ((1) != (1)) 6> XXXTest.c:46 : (XXX : test_06) : ((void*)(&i) == (void*)(&j)) 7> XXXTest.c:51 : (XXX : test_07) : ((void*)(&i) != (void*)(&i)) 8> XXXTest.c:56 : (XXX : test_08) : (NULL == (void*)(&i)) 9> XXXTest.c:61 : (XXX : test_09) : (NULL != (void*)(p)) 10> XXXTest.c:67 : (XXX : test_10) : (0 == strcmp((const char*)x, (const char*)y)) 11> XXXTest.c:73 : (XXX : test_11) : (0 != strcmp((const char*)x, (const char*)y)) 12> XXXTest.c:79 : (XXX : test_12) : (0 == strncmp((const char*)x, (const char*)y, (size_t)4)) 13> XXXTest.c:85 : (XXX : test_13) : (0 != strncmp((const char*)x, (const char*)y, (size_t)3)) 14> XXXTest.c:91 : (XXX : test_14) : (fabs((double)x - y) <= fabs((double)0.2)) 15> XXXTest.c:97 : (XXX : test_15) : (fabs((double)x - y) > fabs((double)0.4)) ======================================= Total Number of Failures : 15 ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| (R)un all, (S)elect group, (L)ist groups, Show (F)ailures, (Q)uit Enter Command : q