Check Tutorial
Prev | Chapter 3. Tutorial: Basic unit testing | Next

# 3.4. Creating a suite

To run unit tests with Check, we must create some test cases, aggregate them into a suite, and run them with a suite runner. That's a bit of overhead, but it is mostly one-off. Here's the code in check_money.c. Note that we include stdlib.h to get the definitions of EXIT_SUCCESS and EXIT_FAILURE.

    #include <stdlib.h>
    #include <check.h>
    #include "money.h"

    START_TEST (test_create)
    {
      Money *m;
      m = money_create(5, "USD");
      fail_unless(money_amount(m) == 5, "Amount not set correctly on creation");
      fail_unless(strcmp(money_currency(m), "USD") == 0,
                  "Currency not set correctly on creation");
      money_free(m);
    }
    END_TEST

    Suite *money_suite(void)
    {
      Suite *s = suite_create("Money");
      TCase *tc_core = tcase_create("Core");

      suite_add_tcase (s, tc_core);
      tcase_add_test(tc_core, test_create);

      return s;
    }

    int main(void)
    {
      int nf;
      Suite *s = money_suite();
      SRunner *sr = srunner_create(s);
      srunner_run_all(sr, CK_NORMAL);
      nf = srunner_ntests_failed(sr);
      srunner_free(sr);
      return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
    }

Most of the money_suite code should be self-explanatory. We are creating a suite, creating a test case, adding the test case to the suite, and adding the unit test we created above to the test case. Why separate this off into a separate function, rather than inlining it in main? Because any new tests will get added in money_suite, but nothing will need to change in main for the rest of this example, so main will stay relatively clean and simple.

Unit tests are internally defined as static functions. This means that the code to add unit tests to test cases must be in the same compilation unit as the unit tests themselves. This provides another reason to put the creation of the test suite in a separate function: you may later want to keep one source file per suite; defining a uniquely named suite creation function allows you later to define a header file giving prototypes for all the suite creation functions, and encapsulate the details of where and how unit tests are defined behind those functions. See the test program defined for Check itself for an example of this strategy.

The code in main bears some explanation. We are creating a suite runner object from the suite we created in money_suite. We then run the suite, using the CK_NORMAL flag to specify that we should print a summary of the run, and list any failures that may have occurred. We capture the number of failures that occurred during the run, and use that to decide how to return. The check target created by Automake uses the return value to decide whether the tests passed or failed.

Prev | Home | Next
Test a little, code a little | Up | SRunner output