[ CCUnit project page ] |  | [ CCUnit home page ]

# CCUnit Cookbook

Here is a short cookbook to help you get started.

[see also Japanese documents]

## Simple Test Case

Tests in CCUnit can be run automatically. They are easy to set up and once you have written them, they are always there to help you keep confidence in the quality of your code.

To make a simple test, here is what you do:

1. Create a test function

2. When you want to check a value, call CCUNIT_ASSERT(bool) and pass a bool that is true if the test succeeds

   ASSERT macro is listed in others as well in Assert Macros.

For example, see the test of the library of the simple complex number as an example. (This sample program is in the `examples/complex` directory) To test whether the initialization of the complex numeber and tow complex numbers are equal.

    void test_complex_new ()
    {
      complex_t* c10_1 = complex_new (10, 1);
      CCUNIT_ASSERT_TEST (double, 10, ==, c10_1->real);
      CCUNIT_ASSERT_TEST (double, 1, ==, c10_1->imaginary);
      complex_delete (c10_1);
    }

    void test_complex_equals ()
    {
      complex_t* c10_1 = complex_new (10, 1);
      complex_t* c10_1_2 = complex_new (10, 1);
      complex_t* c1_1 = complex_new (1, 1);
      CCUNIT_ASSERT (complex_equals (c10_1, c10_1_2));
      CCUNIT_ASSERT (complex_equals (c10_1, c1_1) == 0);
      complex_delete (c10_1);
      complex_delete (c10_1_2);
      complex_delete (c1_1);
    }

These two test functions are made one test case together, and we can run it.

Include the necessary header files.

    #include <ccunit/CCUnitTestCase.h>
    #include <ccunit/CCUnitTestResult.h>

First, Allocate the test case memory.

    extern void test_complex_new ();
    extern void test_complex_equals ();

    int main ()
    {
      CCUnitTestCase* testCase;
      CCUnitTestResult* result;
      bool success;
      testCase = ccunit_newTestCase ("complex test");

Then, register the test functions in the test case. The assertion should specify the name of the function and the explanation of the function to indicate it at the unsuccessful time.

      ccunit_addNewTestFunc (testCase,
                             "test_complex_new",
                             "test new",
                             test_complex_new);
      ccunit_addNewTestFunc (testCase,
                             "test_complex_equals",
                             "complex equals test",
                             test_complex_equals);

Run the test case, and take out the result.

      result = ccunit_runTestCase (testCase);
      success = ccunit_wasSuccessful (result);

Deallocate the memory whitch you assigned, and return the result.

      ccunit_deleteTestCase (testCase);
      ccunit_deleteTestResult (result);
      return success ? 0 : -1;
    }

You find the sample code made in the above in the files `testComplex.c` and `runTestCase.c` in the `examples/complex` directory.

To compile and run, do the following:

    $ gcc -o runTestCase runTestCase.c testComplex.c complex.c -lccunit
    $ ./runTestCase
    $ echo $?
    0

When the test case is run, that specific test functions will be run. This is not a useful thing to do, however, as no diagnostics will be displayed. One will normally use a Executing Test to display the results.

## TestRunner

How do you run your tests and collect their results? The TestCase store result of own tests into the TestResult. At the same time, the test case informs the TestRunner of the executive conditionsn of the test.

Once you have a test suite, you'll want to run it. CCUnit provides TestRunner to define the suite to be run and to display its results.

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

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

First, make the TestSuite, and register the TestCase.

    extern void test_complex_new ();
    extern void test_complex_equals ();

    int main ()
    {
      CCUnitTestCase* testCase;
      CCUnitTestSuite* suite;
      CCUnitTestRunner* runner;
      int ret;
      testCase = ccunit_newTestCase ("complex test");
      ccunit_addNewTestFunc (testCase,
                             "test_complex_new",
                             "test new",
                             test_complex_new);
      ccunit_addNewTestFunc (testCase,
                             "test_complex_equals",
                             "complex equals test",
                             test_complex_equals);
      suite = ccunit_newTestSuite ("complex test suite");
      ccunit_addTestCase (suite, testCase);

And call to ccunit_runTestRunner(CCUnitTestRunner*, CCUnitTestSuite *):

      runner = ccunit_newTestRunner (stdout);
      ret = ccunit_runTestRunner (runner, suite);

Deallocate the memories.

      ccunit_deleteTestRunner (runner);
      ccunit_deleteTestSuite (suite);
      /* ccunit_deleteTestCase (testCase); // testCase deleted when suite was deleted */
      return ret;
    }

The sample code made in the above is in the directory `examples/complex`, the files `testComplex.c, complexTestSuite.c` and `runTestRunner.c`.

To compile and run, do the following:

    $ gcc -o runTestCaseRunner runTestCaseRunner.c testComplex.c complex.c -lccunit
    $ ./runTestCaseRunner
    ..
    Time: 0.000027 sec

    OK (2 tests)

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(bool) which detected the failure

For example, try to mistake it in the test case of `testComplex.c` on purpose.

    void test_complex_equals ()
    {
      ...
      CCUNIT_ASSERT (complex_equals (c10_1, c10_1_2));
    /*CCUNIT_ASSERT (complex_equals (c10_1, c1_1) == 0);*/
      CCUNIT_ASSERT (complex_equals (c10_1, c1_1) != 0);
      ...
    }

    $ gcc -o runTestCaseRunner runTestCaseRunner.c testComplex.c complex.c -lccunit
    $ ./runTestRunner
    ..F
    Time: 0.000036 sec

    FAILURES!!!
    Test Results:
    Run 2, Failures 1
    There was 1 failure:
    testComplex.c:46: complex equals test:
            complex_equals (c10_1, c1_1) != 0

In this example, two test cases are run. Then, you will see that the second is unsuccessful.

That was a very simple test. Ordinarily, you'll have many little test cases that you'll want to run on the same set of objects. To do this, use global variables.

## setUp and tearDown

What if you have two or more tests that operate on the same similar set of objects?

Tests need to run against the background of a known set of data. you are writing tests you will often find that you spend more time writing the code to set up the data than you do in actually testing values.

In the sample code of the previous section, some complex numbers are allocated, and it is deleted.

Often, you will be able to use the same data for several different tests. Each case will assign slightly different values to the data and will check for different results. Then, if the test is finished, clean-up the data. The function `setUp` and `tearDown` are used at such time.

When you have a common global variables, here is what you do:

Define the global variable.

    #include "complex.h"

    static complex_t* c10_1;

Write the function `setUp` to allocate the complex.

    void setUp_test_complex ()
    {
      c10_1 = complex_new (10, 1);
    }

Write the function `tearDown` to delete the memory of that complex.

    void tearDown_test_complex ()
    {
      complex_delete (c10_1);
    }

Write the test function.

    void test_complex_new ()
    {
      CCUNIT_ASSERT_TEST (double, 10, ==, c10_1->real);
      CCUNIT_ASSERT_TEST (double, 1, ==, c10_1->imaginary);
    }

    void test_complex_equals ()
    {
      complex_t* c10_1_2 = complex_new (10, 1);
      complex_t* c1_1 = complex_new (1, 1);
      CCUNIT_ASSERT_TEST_OBJ (c10_1, complex_equals, c10_1_2, complex_to_string);
      CCUNIT_ASSERT_TEST_OBJ (c10_1, !complex_equals, c1_1, complex_to_string);
      complex_delete (c10_1_2);
      complex_delete (c1_1);
    }

Register the function `setUp` and `tearDown`. At this time, the name of the function must have begun with `"setUp"` or `"tearDown"`.

    int main ()
    {
      CCUnitTestCase* testCase;
      CCUnitTestSuite* suite;
      CCUnitTestRunner* runner;
      int ret;
      testCase = ccunit_newTestCase ("complex test");
      ccunit_addNewTestFunc (testCase,
                             "setUp_test_complex",
                             "setUp_test_complex",
                             setUp_test_complex);
      ccunit_addNewTestFunc (testCase,
                             "tearDown_test_complex",
                             "tearDown_test_complex",
                             tearDown_test_complex);

Run the test case, and return the result.

      ccunit_addNewTestFunc (testCase,
                             "test_complex_new",
                             "test new",
                             test_complex_new);
      ccunit_addNewTestFunc (testCase,
                             "test_complex_equals",
                             "complex equals test",
                             test_complex_equals);
      suite = ccunit_newTestSuite ("complex test suite");
      ccunit_addTestCase (suite, testCase);
      runner = ccunit_newTestRunner (stdout);
      ret = ccunit_runTestRunner (runner, suite);
      ccunit_deleteTestRunner (runner);
      ccunit_deleteTestSuite (suite);
      return ret;
    }

The sample code made in the above is in the directory `examples/complex`, the files are `testComplexSetup.c` and `runTestCaseSetup.c`.

To compile and run, do the following:

    $ gcc -o runTestCaseSetup runTestCaseSetup.c testComplexSetup.c complex.c -lccunit
    $ ./runTestCaseSetup
    ..
    Time: 0.000048 sec

    OK (2 tests)

## setUp/tearDown of only one time

In the previous section, the initialization was done in every test every time. But we do the initialization only once, and we may run the multiple test. Then, only when all the tests are finished, it may seem to carry out the code for the settlement.

You register the `setUp` and `tearDown` function in the test case for that. Then, the test functions are run in the following order:

## Suite

How do you set up your tests so that you can run them all at once? Once you have several tests, organize them into a suite.

CCUnit provides a TestSuite module that runs any number of TestFuncs together. You saw, above, how to run test suite.

To create a suite of two or more tests, you do the following:

Create two test cases, and register test functions to each cases.

    int main ()
    {
      CCUnitTestCase* testCase, * testArith;
      CCUnitTestSuite* suite;
      CCUnitTestRunner* runner;
      int ret;
      /* test complex */
      testCase = ccunit_newTestCase ("test complex");
      ccunit_addNewTestFunc (testCase,
                             "setUp_test_complex",
                             "setUp_test_complex",
                             setUp_test_complex);
      ccunit_addNewTestFunc (testCase,
                             "tearDown_test_complex",
                             "tearDown_test_complex",
                             tearDown_test_complex);
      ccunit_addNewTestFunc (testCase,
                             "test_complex_new",
                             "test new",
                             test_complex_new);
      ccunit_addNewTestFunc (testCase,
                             "test_complex_equals",
                             "complex equals test",
                             test_complex_equals);
      /* test complex arith */
      testArith = ccunit_newTestCase ("test complex arith");
      ccunit_addNewTestFunc (testArith,
                             "setUp_test_complex_arith",
                             "setUp_test_complex_arith",
                             setUp_test_complex_arith);
      ccunit_addNewTestFunc (testArith,
                             "tearDown_test_complex_arith",
                             "tearDown_test_complex_arith",
                             tearDown_test_complex_arith);
      ccunit_addNewTestFunc (testArith,
                             "test_complex_add",
                             "test add",
                             test_complex_add);
      ccunit_addNewTestFunc (testArith,
                             "test_complex_sub",
                             "test sub",
                             test_complex_sub);
      ccunit_addNewTestFunc (testArith,
                             "test_complex_mul",
                             "test mul",
                             test_complex_mul);
      ccunit_addNewTestFunc (testArith,
                             "test_complex_div",
                             "test div",
                             test_complex_div);

Create a test suite, then register that two test cases to it.

      suite = ccunit_newTestSuite ("complex test suite");
      ccunit_addTestCase (suite, testCase);
      ccunit_addTestCase (suite, testArith);

Create test runner and run the tests.

      runner = ccunit_newTestRunner (stdout);
      ret = ccunit_runTestRunner (runner, suite);
      ccunit_deleteTestRunner (runner);
      ccunit_deleteTestSuite (suite);
      return ret;
    }

The sample code made in the above is in the directory `examples/complex`, the files are `runTestSuite.c`, `testComplexSetup.c` and `testComplexArith.c`.

To compile and run, do the following:

    $ gcc -o runTestSuite runTestSuite.c testComplexSetup.c testComplexArith.c complex.c -lccunit
    $ ./runTestSuite
    ......
    Time: 0.000061 sec

    OK (6 tests)

TestSuites don't only have to contain TestCases . They can also contain TestSuites. For example, you can create a TestSuite in your code and I can create one in mine, and we can run them together by creating a TestSuite that contains both:

      CCUnitTestSuite* suite;
      CCUnitTestSuite* suite_a;
      CCUnitTestSuite* suite_b;

      ...

      suite = ccunit_newTestSuite ("complex all test suite");
      suite_a = ccunit_newTestSuite ("complex test suite A");
      suite_b = ccunit_newTestSuite ("complex test suite B");

      ...

      ccunit_addTestSuite (suite, suite_a);
      ccunit_addTestSuite (suite, suite_b);

## Helper Tool

As you might have noticed, the work to register the test function in the test case and to register the test case in the test suite is easy to mistake concerning the repetition.

Actually, though the test function of `test_complex_to_string()` was defined in `testComplexSetup.c`, it was ignored by the above explanation, and it didn't register for the test case.

A Creating TestSuite set of functions and command have been created to automatically implements the creating suite function.

You make the file which you write the test case in for that as follows.

First, declare the test suite as this in the comment of the javaDoc style. As for the comment of the javaDoc style, the starts of the comment block of the C style are two asterisks "<tt>**</tt>".

    /** test suite: complex test suite */

Next, define the test cases. The test case is gathering of the global variables and the functions that surrounded in the declaration of the end of the test case with the declaration of the name of the test case written in the comment of the javaDoc style.

One file can define the multiple test case.

    /** test case: complex test case */

    static complex_t* c10_1;

    /** test new */
    void test_complex_new ()
    {
      ...
    }

    ...

    /** end test case */
    /** test case: complex arith test case */
    ...
    /* end test case */
    /* end test suite */
    /* test suite: ... */
    ...
    /* end test suite */

As for the test function, the name must have begup with test. You can write the explanation of the test function in the comment of the javaDoc style before each test function. If the comment isn't being written, the name of the test function is registered as an explanation of the function.

There are `setUp`, `tearDown`, `setup_setUp` and `setup_tearDown` as a special test function. Their works as a functional function of the test case that Those function as a functional function of the test case which I explained before so that you may know it from that name. Define as the function to begin respectively with such a name.

To generate creating suite function code, run `ccunit_makeSuite` tool.

The function to make TestSuite is `ccunit_suite`. But, it can be changed to another name by the `-f` option of the `ccunit_makeSuite` command, too.

    $ ccunit_makeSuite -f suite_test_complex -o suiteTestComplex.c testComplexSetup.c testComplexArith.c

The next is taken to use the code which you generated automatically.

Declare the prototype of the function which you generated. Try not to forget `char* name` of the argument.

    #include <stdio.h>
    #include <ccunit/CCUnitTestSuite.h>
    #include <ccunit/CCUnitTestRunner.h>

    extern CCUnitTestSuite* suite_test_complex (char* name);

Call the function which you generated, and take out the test suite.

    int main ()
    {
      CCUnitTestSuite* suite;
      CCUnitTestRunner* runner;
      int ret;
      suite = suite_test_complex ("complex suite auto generated");

Run it by the test runner.

      runner = ccunit_newTestRunner (stdout);
      ret = ccunit_runTestRunner (runner, suite);
      ccunit_deleteTestRunner (runner);
      ccunit_deleteTestSuite (suite);
      return ret;
    }

The sample code here will be found with `runTestSuite.c`, `testComplex.c` and `testComplexArith.c` of the `examples/complex` dhirectory.

To compile and run, do the following:

    $ ccunit_makeSuite -f suite_test_complex -o suiteTestComplex.c testComplexSetup.c testComplexArith.c
    $ gcc -o runTestSuiteAuto runTestSuiteAuto.c testComplexSetup.c testComplexArith.c suiteTestComplex.c complex.c -lccunit
    $ ./runTestSuiteAuto
    .......
    Time: 0.000060 sec

    OK (7 tests)

To generate a code, the test case source codes must be formatted by following pseudo-BNF:

     SOURCEFILE ::= [SUITE]... | TESTCASE...

     SUITE ::= SUITE_HEADER
               [ any-C-code ]...
               TESTCASE...
               SUITE_END

     SUITE_HEADER ::= JAVADOC_COMMENT_BEGIN 'test suite:' SUITE_NAME COMMENT_END
     SUITE_END ::= JAVADOC_COMMENT_BEGIN 'end test suite' wsp string COMMENT_END

     TESTCASE ::= TESTCASE_HEADER
                 [TESTCASE_CODE]...
                 [TESTFUNC]...
                 TESTCASE_END

     TESTCASE_HEADER ::= JAVADOC_COMMENT_BEGIN
                        'test case:' TESTCASE_NAME
                        COMMENT_END
     TESTCASE_CODE ::= any C language codes.

     TESTFUNC ::= [ FUNC_DESC ] 'void ' FUNC_PREFIX[A-Za-z0-9_]* '()' FUNC_BODY

     FUNC_PREFIX ::= 'test' | 'setUp' | 'tearDown' | 'setup_setUp' | 'setup_tearDown'

     TESTCASE_END ::= JAVADOC_COMMENT_BEGIN 'end test case ' [string] COMMENT_END

     FUNC_DESC ::= JAVADOC_COMMENT_BEGIN string COMMENT_END

     FUNC_BODY ::= '{' C language codes... '}'

     JAVADOC_COMMENT_BEGIN ::= '/' '*' '*'
     COMMENT_END ::= '*' '/'

## Sample Programs

The sample program made in the above is in the `examples/complex` directory.

- complex - some complex number library test cases

- libcomplex.a - complex number library
  - complex.c
  - complex.h
- runTestCase
  - runTestCase.c - main program
  - testComplex.c - test cases
- runTestCaseRunner
  - runTestCaseRunner.c - main program
  - testComplex.c - test cases
- runTestCaseSetup
  - runTestCaseSetup.c - main program
  - testComplexSetup.c - test cases
- runTestSuite
  - runTestSuite.c - main program
  - testComplexSetup.c - test cases
  - testComplexArith.c - test cases
- runTestSuiteAuto
  - runTest.c - main program
  - testComplexSetup.c - test cases
  - testComplexArith.c - test cases
  - suiteTestComplex.c - auto generated test suite.

| hosts this site. |  | Send comments to: CCUnit Developer |