Fork us on GitHub Follow us on Google+ Follow us on Facebook Follow us on Twitter

Userspace unit testing with PCUT

PCUT - plain C unit testing - is (still somewhat experimental) framework/library that ought to simplify writing unit tests in C. Its main advantage is simple usage and integration with HelenOS.

PCUT itself is a standalone project with its own wiki. This page provides mostly information specific for HelenOS (at least for now).

Building and running PCUT tests

The PCUT tests are built by default but are not included in the final image unless explicitly enabled. To enable them, turn on the Include userspace unit tests (PCUT) option during HelenOS configuration.

The tests then reside in the test/ directory, named test-<component> where <component> may refer to a standalone application or a library. It is possible to run them separately by launching individual binaries or run them all with the following command:

batch /test/run_all

This batch script also copies the result to /data/web, thus making them accessible by simply pointing your browser to /test.html (assuming you started the HelenOS web server).

The tests output their results in a Test-Anything-Protocol format that is easy to understand, below is an example from successful run of test-libc:

1..11
#> Starting suite sprintf.
ok 1 no_formatting
ok 2 string_plain
ok 3 string_dynamic_width
ok 4 string_dynamic_width_align_left
ok 5 string_pad
ok 6 string_pad_but_cut
ok 7 char_basic
ok 8 int_various_padding
ok 9 int_negative_various_padding
ok 10 long_negative_various_padding
ok 11 int_as_hex
#> Finished suite sprintf (failed 0 of 11).

Writing your own tests

The test sources are typically stored in a test/ subdirectory of the application/library they are testing. If you want to extend already existing test case or add a new test case, open an existing file with the tests and add it there. The file may look like this (example taken from bdsh):

/* ... */

static tokenizer_t tokenizer;
static token_t tokens[MAX_TOKENS];

/*
 * Implementation of
 * void prepare(const char *input, size_t expected_token_count)
 * is omitted.
 */

#define ASSERT_TOKEN(index, token_type, token_text) \
        do { \
                PCUT_ASSERT_INT_EQUALS(token_type, tokens[index].type); \
                PCUT_ASSERT_STR_EQUALS(token_text, tokens[index].text); \
        } while (0)



PCUT_TEST_SUITE(tokenizer);

PCUT_TEST_AFTER {
        /* Destroy the tokenizer. */
        tok_fini(&tokenizer);
}


PCUT_TEST(empty_input) {
        prepare("", 0);
}

PCUT_TEST(only_spaces) {
        prepare("   ", 1);

        ASSERT_TOKEN(0, TOKTYPE_SPACE, "   ");
}

PCUT_TEST(two_text_tokens) {
        prepare("alpha  bravo", 3);

        ASSERT_TOKEN(0, TOKTYPE_TEXT, "alpha");
        ASSERT_TOKEN(1, TOKTYPE_SPACE, "  ");
        ASSERT_TOKEN(2, TOKTYPE_TEXT, "bravo");
}

PCUT_MAIN()

Individual test cases are enclosed in PCUT_TEST(test_name), available asserts are listed here. You might also want to read how to create test suites that may share a set-up and tear-down code. It is also possible to split the tests into more files.

Adding tests to previously untested code

It is recommended to put the test sources under test/ directory to separate them from the tested code.

Add sources with the tests to the TEST_SOURCES variable. If your are testing a library, the test executable will be automatically linked with it. For an application (or server), you need to add all the necessary source files by yourself (it is not possible to add all of them automatically because PCUT creates its own main() function that would collide with the main() of the application).

Add path to the test to the RD_TESTS variable in boot/Makefile.common.

Basically, look how it is done for existing tests (libc, libposix, liburi or bdsh) until this how-to is improved.

Last modified 4 years ago Last modified on 2014-10-13T15:31:03Z