株式会社エス・スリー・フォー

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と期待する文字列expectedcountが一致しなかったとき、

    すなわちstrncmp(expected,actual, count)
    != 0 のときに失敗します。

  • ASSERT_NSTRING_NOT_EQUAL(
    expected, actual, count
    );

    得られた結果actualと期待する文字列expectedcountが一致したとき、

    すなわち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