오픈 소스 소프트웨어 개발 및 다운로드

View クックブック

category(Tag) tree

file info

category(Tag)
root
file name
Cookbook
마지막 업데이트
2003-10-24 00:12
type
HTML
editor
TSUTSUMI Kikuo
description
CCUnitをつかってテストを実装するためのクックブック
language
English
Japanese
translate
CCUnit project page CCUnit home page

CCUnit クックブック

これは CCUnit を使い始めるにあたって、 理解の助けとなるような短いクックブックです。

[see also English documents]

シンプルなテストケース

CCUnitを使ったテストは自動的に実行することができます。 CCUnit のテストは簡単にセットアップすることができ、 一度テストを書いてしまえば、 いつでもプログラムの品質を信頼できるものに保つことができるでしょう。

単純なテストを作るには、次のようにします。

  1. テスト関数を作る
  2. 値をチェックしたい場合は、CCUNIT_ASSERT(bool) を呼び出して、 もしテストが成功するのであれば真を返すような真偽値を渡します

例えば、二つの複素数の合計が、 二つの複素数の値を加算した値と同じであることをテストするとします。

void test_complex_add ()
{
  complex_t c10_1 = { 10.0, 1.0 };
  complex_t c1_1 = { 1.0, 1.0 };
  complex_t result;
  complex_t c11_2 = { 11.0, 2.0 };
  CCUNIT_ASSERT (complex_equals (&c11_2, complex_add (&result, c10_1, c1_1)));
}

これは大変単純なテストです。 通常、同じデータのセットで走らせるために、 たくさんの小さなテストケースを作らなければならないでしょう。 そうするにはフィクスチャ(備品)を使います。

フィクスチャ

もし二つ以上のテストがあるなら、 同じ類似のデータのセットで操作するのではないでしょうか。

テストは周知のデータのセットを背景にして実行される必要があります。 このデータのセットをフィクスチャと呼ぶことにします。 テストを書いていると、 実際のテストする値をフィクスチャにセットアップするコードを書く方に、 もっと時間をかけていることに気づくことがよくあります。

多くの場合、いくつかの異なったテストのために同じフィクスチャを使うことができます。 それぞれのテストケースは少し異なったメッセージ、 あるいはパラメータをフィクスチャに送り、 異なる結果を調べます。

もし共通するフィクスチャがあれば、こんなふうにすることになり ます。

  1. TestCase 構造体にメモリを割り当てます (以降、構造体に割り当てたメモリを、オブジェクトと呼ぶことにします)
  2. フィクスチャのそれぞれの部分に大域変数を追加します
  3. setUp() 関数を書いて変数を初期化します
  4. tearDown() 関数を書いてsetUp で割り当てた永続的リソースを解放します
  5. CCUnitTestFixture 構造体にメモリを割り当てます
  6. CCUnitTestFixture 構造体にメモリを割り当てます

例えば、いくつかのテストケースを書く場合、 最初にフィクスチャを作成します。

/** TEST CASE: complex number test */

#include "complex.h"

static complex_t* s10_1;
static complex_t* s1_1;
static complex_t* s11_2;

void setUp_ComplexTest ()
{
  s10_1 = complex_new (10, 1);
  s1_1 = complex_new (1, 1);
  s11_2 = complex_new (11, 2);
}

void tearDown_ComplexTest ()
{
  complex_delete (s10_1);
  complex_delete (s1_1);
  complex_delete (s11_2);
}

...

  CCUnitTestFixture* fixture;
  fixture = ccunit_newTestFixture ("ComplexTest",
                                   CCUNIT_NEWTESTFUNC(setUp_ComplexTest),
                                   CCUNIT_NEWTESTFUNC(tearDown_ComplexTest));

一度決まったところにフィクスチャを書いてしまえば、 あなたが好きなように複素数のテストケースを書くことができます。

テストケース

フィクスチャを一つ書いたとして、 どうやって個々のテストケースを書いて実行すれば良いでしょうか。

例えば、二つの複素数が等しい(または等しくない)ことをテストするには、 次のように書きます。

void test_complex_equals ()
{
  CCUNIT_ASSERT_TEST_OBJ (s10_1, complex_equals, s10_1, complex_to_string);
  CCUNIT_ASSERT_TEST_OBJ (s10_1, !complex_equals, s1_1, complex_to_string);
}

...

  ccunit_addNewTestCase (fixture,
                         "test_complex_equals",
                         "complex equals test",
                         test_complex_equals);
  ccunit_addNewTestCase (fixture,
                         "test_complex_add",
                         "complex add test",
                         test_complex_add);

一つには次のように、 フィクスチャを作成してそれぞれのテストケースを実行させること ができます。

  CCUnitTestResult* result;
  result = ccunit_runTestFixture (fixture);

テストフィクスチャが実行されると、 特定のテスト関数が呼び出されます。 これはあまり便利ではありません、 なぜなら、診断が表示されないからです。 通常は TestRunner (テストランナー 後述) で結果を表示します。

一度いくつかのテストを作ったら、 それらをスイートに整理します。

スイート

どのようにして、一度にテストを実行することができるよう、 準備したらいいでしょうか?

CCUnit はいくつもの TestCases を一緒に実行する TestSuite モジュールを提供します。

テストフィクスチャを実行する方法は上述しました。

二つ以上のテストを含む一つのスイートを作るには、次のようにします。

CCUnitTestSuite* suite;
CCUnitTestFixture* fixture;
CCUnitTestResult* result;
suite = ccunit_newTestSuite ("Complex test suite");
fixture = ccunit_newTestFixture ("Complex Tests",
                                 CCUNIT_NEWTESTFUNC(setUp_complex_test),
                                 CCUNIT_NEWTESTFUNC(tearDown_complex_test));
ccunit_addNewTestCase (fixture, "test_complex_equals", "complex equals test",
                       test_complex_equals);
ccunit_addNewTestCase (fixture, "test_complex_add", "complex add test",
                       test_complex_add);
ccunit_addNewTestCase (fixture, "test_complex_sub", "complex sub test",
                       test_complex_sub);
ccunit_addTestFixture (suite, fixtuer);
result = ccunit_runTestSuite (suite, NULL);

TestSuites TestFixtures を含むだけではありません。 それらは Test インタフェースを実装するどんなオブジェクトでも含められます。 例えば、あなたはあなたのコードにTestSuite を作ることができ、そして私は私のスイートを作ることができます、 そして私達は両方ともを含んでいる TestSuite を作って一緒に個々のスイートを動かすことができるのです。

CCUnitTestSuite* suite;
CCUnitTestResult* result;
suite = ccunit_newTestSuite ("suite");
ccunit_addTestSuite (suite, complex_add_sub_suite ());
ccunit_addTestSuite (suite, complex_mul_div_suite ());
result = ccunit_runTestSuite(suite, NULL);

テストランナー

どうやってテストを実行し、その結果を集めたら良いでしょうか。

一つテストスイートを書いたら、 それを実行したいでしょう。 CCUnit はスイートを実行するために定義し、 結果を表示するためのツールを提供します。 スーツをccunit_makeSuite ツールに入力できるような形式で書くことで、 テストスーツを作成するコードを自動的に生成することができます。

例えば、ComplexTest スイートを ccunit_makeSuite を使って使用できるようにするには、 以下のツールを ComplexTest.c に実行します。

$ ccunit_makeSuite -f complex_suite -o suiteComplex.c ComplexTest.c

TestRunner を使用するには、 Main.cでテストのためのファイルのヘッダをインクルードします。

そしてccunit_runTestRunner (CCUnitTestRunner*, CCUnitTestSuite *) main()関数で実行します。

extern CCUnitTestSuite* complex_suite(const char* name);

int main( int argc, char **argv)
{
  CCUnitTestRunner* runner;
  CCUnitTestSuite* suite;
  runner = ccunit_newTestRunner (stdout);
  suite = complex_suite ("complex test suite");
  return ccunit_runTestRunner (runner, suite);
}

TestRunner はテストを実行します。 もしすべてのテストがパスすれば、その情報のメッセージが表示されます。 もしどれかが失敗すれば、それについて以下のような情報が表示されます。

  • テストを含んでいるソースファイル名
  • 失敗が怒った行番号
  • 失敗したテストケースの名前
  • 失敗を検知したCCUNIT_ASSERT ()が呼び出された時の条件の文字列。

ヘルパーツール

お気づきのように、フィクスチャの suite ()関数を実装するのは、 反復的で間違いやすい作業です。 Creating TestSuite の関数のセットとコマンドはsuite () 関数の実装を自動的に作成することができます。

以下のコードはそれらのコマンドが使うようにComplexTestを書換えたものです。

#include <cppunit/CCUnitAssert.h>

最初に、フィクスチャを宣言します。 これはjavaDocスタイルのコメント内にフィクスチャの名前を記述します。 javaDocスタイルのコメントとは C スタイルのコメントブロックの開始が 二つのアスタリスク*になっているものです。

/** test case: complex number test */

TestSuite を作成する関数は ccunit_suite です、 しかし ccunit_makeSuite コマンドの -f オプションで別の名前に変えることもできます。 そして、フィクスチャのテストケースにはそれぞれ名前の先頭に、 test, setUp, tearDown をつけてください。

#include <complex.h>

static complex_t* s10_1;
static complex_t* s1_1;
static complex_t* s11_2;

void setUp_complex_test ()
{
  s10_1 = complex_new (10, 1);
  s1_1 = complex_new (1, 1);
  s11_2 = complex_new (11, 2);
}

void tearDown_complex_test ()
{
  complex_delete (s10_1);
  complex_delete (s1_1);
  complex_delete (s11_2);
}

/** test equals */
void test_complex_equals ()
{
  CCUNIT_ASSERT_TEST_OBJ (s10_1, complex_equals, s10_1, complex_to_string);
  CCUNIT_ASSERT_TEST_OBJ (s10_1, !complex_equals, s1_1, complex_to_string);
}

/** test add */
void test_complex_add ()
{
  complex_t c10_1 = { 10.0, 1.0 };
  complex_t c1_1 = { 1.0, 1.0 };
  complex_t result;
  complex_t c11_2 = { 11.0, 2.0 };
  CCUNIT_ASSERT (complex_equals (&c11_2, complex_add (&result, &c10_1, &c1_1)));
}

/** test sub */
void test_complex_sub ()
{
  complex_t c9_0 = { 9, 0 };
  complex_t result;
  CCUNIT_ASSERT_TEST_OBJ (&c9_0, complex_equals,
                          complex_sub (&result, s10_1, s1_1),
                          complex_to_string);
}

最後に、フィクスチャの終りを宣言します。

/** end test case */

スイート作成関数のコードを生成するには、 ccunit_makeSuiteツールを実行します。

$ ccunit_makeSuite -f complex_suite -o suiteComplex.c testComplex.c
$ cat suiteComplex.c

#include <ccunit/CCUnitTestSuite.h>
#include <ccunit/CCUnitTestFixture.h>
#include <ccunit/CCUnitTestCase.h>

/* test fixture: complex number test */
/* setUp_complex_test */
extern void setUp_complex_test ();
/* tearDown_complex_test */
extern void tearDown_complex_test ();
/* test_complex_equals */
extern void test_complex_equals ();
/* test_complex_add */
extern void test_complex_add ();
/* test_complex_sub */
extern void test_complex_sub ();

static CCUnitTestFunc fx_001_cases[] = {
  {
    "test_complex_equals",
    "test equals",
    test_complex_equals
  },
  {
    "test_complex_add",
    "test add",
    test_complex_add
  },
  {
    "test_complex_sub",
    "test sub",
    test_complex_sub
  },
  {
    NULL, NULL, NULL
  },
};

static CCUnitTestFixtureDfn fx_001 = {
  { ccunitTypeFixture },
  "complex number test",
  {
    "setUp_complex_test",
    "setUp_complex_test",
    setUp_complex_test
  },
  {
    "tearDown_complex_test",
    "tearDown_complex_test",
    tearDown_complex_test
  },
  fx_001_cases,
};

static CCUnitTestDfn* suite_001_test[] = {
    &fx_001.test,
    NULL,
};

static CCUnitTestSuiteDfn suite_001 = {
  { ccunitTypeSuite },
  "",
  suite_001_test
};


CCUnitTestSuite* complex_suite (const char* name)
{
  if (!suite_001.name[0])
    suite_001.name = name;
  return ccunit_newTestSuiteFromDfn (&suite_001);
}
$

ビルド後のチェック

さあユニットテストを実行する準備ができました。 ではビルドプロセスにユニットテストを統合するにはどうしたらい いでしょう。

そうするには、アプリケーションは、エラーが発生したことを示す 0以外の値を返さなければなりません。

ccunit_runTestRunner() は、実行が成功したかどうかを示す整数を返します。

次のようにメインプログラムを更新します。

#include <ccunit/CCUnitTestRunner.h>

int main (int argc, char** argv)
{
  CCUnitTestRunner* runner;
  CCUnitTestSuite* suite;
  int wasSucessful;
  runner = ccunit_newTestRunner (stdout);
  suite = ccunit_suite ();
  wasSucessful = ccunit_runTestRunner (runner, suite);
  return wasSucessful;
}

それではアプリケーションをコンパイルした後に実行してみましょ う。 以上で作成したサンプルプログラムは example/complex ディレク トリにあります。


SourceForge.jp hosts this site. Send comments to:
CCUnit Developer