View クックブックcategory(Tag) treefile info
CCUnit Cookbook (ja)これは CCUnit を使い始めるにあたって、理解の助けとなるような 短いクックブックです。シンプルなテストケースCCUnitを使ったテストは自動的に実行することができます。 CCUnit のテストは簡単にセットアップすることができて一度テスト を書いてしまえば、いつでもプログラムの品質を信頼できるものに 保つことができるでしょう。単純なテストを作るには、次のようにします。
例えば、二つの複素数の合計が、二つの複素数の値を加算したもの であることをテストするとします。
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 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); TestRunnerHow 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:
#include <ccunit/CCUnitTestRunner.h> #include <ccunit/CCUnitTestSuite.h>
And call to ccunit_runTestRunner (CCUnitTestRunner*, CCUnitTestSuite *) in the
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:
Helper ToolAs you might have noticed, implementing the fixturesuite () 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
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
/** test case: complex number test */
The suite created by the
#include Finally, you end the fixture declaration:
/** end test case */
To generate creating suite function code, run
$ 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 checkNow 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.
|