Open-Source-Software-Entwicklung und Downloads

Anzeigen クックブック

category(Tag) tree

file info

category(Tag)
Wurzel
dateiname
Cookbook
letztes update
2003-10-23 09:03
typ
HTML
editor
TSUTSUMI Kikuo
beschreibung
CCUnitをつかってテストを実装するためのクックブック
sprache
English
Japanese
translate
CCUnit project page CCUnit home page

CCUnit Cookbook (ja)

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

シンプルなテストケース

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

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

/** TEST CASE: 複素数ライブラリテスト */

#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",
                         "複素数等値テスト",
                         test_complex_equals);
  ccunit_addNewTestCase (fixture,
                         "test_complex_add",
                         "複素数加算テスト",
                         test_complex_add);

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

  CCUnitTestResult* result;
  result = ccunit_runTestFixture (fixture);

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

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

スイート

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

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

テストフィクスチャを実行する方法は上述しました。 二つ以上のテストの一つのスイートを作るには、次のようにします。

CCUnitTestSuite* suite;
CCUnitTestFixture* fixture;
CCUnitTestResult* result;
suite = ccunit_newTestSuite ("複素数テストスイート");
fixture = ccunit_newTestFixture ("複素数テスト", 
                                 CCUNIT_NEWTESTFUNC(setUp_complex_test),
                                 CCUNIT_NEWTESTFUNC(tearDown_complex_test));
ccunit_addNewTestCase (fixture, "test_complex_equals", "複素数等値テスト",
                       test_complex_equals);
ccunit_addNewTestCase (fixture, "test_complex_add", "複素数加算テスト",
                       test_complex_add);
ccunit_addNewTestCase (fixture, "test_complex_sub", "複素数減算テスト",
                       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);

TestRunner

How do you run your tests and collect their results?

Once you have a test suite, you'll want to run it. CCUnit provides tools to define the suite to be run and to display its results. You make your suite accessible to a ccunit_makeSuite tool that generate a creating test suite code.

For example, to make a ComplexTest suite available to a ccunit_makeSuite , excute the following tool to ComplexTest.c:

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

To use the TestRunner, include the header files for the tests in Main.c:

And call to ccunit_runTestRunner (CCUnitTestRunner*, CCUnitTestSuite *) in the main() function:

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);
}

The TestRunner will run the tests. If all the tests pass, you'll get an informative message. If any fail, you'll get the following information:

  • The name of the source file that contains the test
  • The line number where the failure occurred
  • The name of the test case that failed
  • All of the text inside the call to CCUNIT_ASSERT () which detected the failure

Helper Tool

As you might have noticed, implementing the fixture suite () function is a repetitive and error prone task. A Creating TestSuite set of functions and command have been created to automatically implements the suite() method.

The following code is a rewrite of ComplexTest using those command:

#include <cppunit/CCUnitAssert.h>

First, you declare the fixture, passing the test fixture name to the javaDoc style comment, which consist of a C-style comment block starting with two *'s:

/** test case: complex number test */

The suite created by the ccunit_suite() function is specified -f option of command ccunit_makeSuite. Then, you define each test case of the fixture with prefix 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);
}

Finally, you end the fixture declaration:

/** end test case */

To generate creating suite function code, run ccunit_makeSuite tool.

$ ccunit_makeSuite testComplex.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 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
  },
  {
    {
      "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 CCUnitTestSuiteDfn suite_001 = {
  { ccunitTypeSuite },
  "",
  {
    &suite_002.test,
    NULL,
  },
};

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

Post-build check

Now that we have our unit tests running, how about integrating unit testing to our build process ?

To do that, the application must returns a value different than 0 to indicate that there was an error.

ccunit_runTestRunner() returns a integer indicating if the run was successful.

Updating our main programm, we obtains:

#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;
}

Now, you need to run your application after compilation.


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