Description
Check is a simple and minimalistic unit testing framework for C. It’s easy to learn and easy to install.
Setup
Most of us will get away with either
apt-get install check
or
yum install check
.
The simplest possible Makefile would look something like this:
CC=gcc CFLAGS=-c -Wall LDFLAGS=-lcheck -lrt -lpthread -lm all: run_tests run_tests: run_tests.o my_tests.o $(CC) $^ -o $@ $(LDFLAGS) .c.o: $(CC) $(CFLAGS) $< -o $@ clean: rm -f *.o *~ run_tests
Functionality
Check is really small, so this section is quite comprehensive.
Test Organization
Tests are grouped into suites, which are divided into test cases. A test case may contain multiple tests. I find the grouping into test cases the least useful; mainly because it’s only made visible for failing tests.
#include <check.h> START_TEST (sample_test) { ck_assert_int_eq(42, 42); } END_TEST Suite *create_sample_suite(void) { Suite *suite = suite_create("Sample suite"); TCase *test_case = tcase_create("Sample test case"); tcase_add_test(test_case, sample_test); return suite; }
To run the tests, I always use the same file. The header file tests.h
contains definitions of all test suite names.
#include <check.h> #include <stdlib.h> #include "tests.h" int main(void) { int number_failed; SRunner *runner = srunner_create(create_sample_suite()); srunner_add_suite(runner, <another suite would go here>); srunner_run_all(runner, CK_NORMAL); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
Integer Assertions
#include <check.h> START_TEST (int_eq) { ck_assert_int_eq(42, 42); } END_TEST START_TEST (int_ne) { ck_assert_int_ne(42, 21); } END_TEST START_TEST (int_lt) { ck_assert_int_lt(41, 42); } END_TEST START_TEST (int_le) { ck_assert_int_le(41, 42); ck_assert_int_le(42, 42); } END_TEST START_TEST (int_gt) { ck_assert_int_gt(43, 42); } END_TEST START_TEST (int_ge) { ck_assert_int_ge(42, 42); ck_assert_int_ge(43, 42); } END_TEST Suite *create_integer_assertions_suite(void) { Suite *suite = suite_create("Integer assertions"); TCase *eq_case = tcase_create("Equality"); tcase_add_test(eq_case, int_eq); tcase_add_test(eq_case, int_ne); TCase *ltgt_case = tcase_create("Less than/Greater than"); tcase_add_test(ltgt_case, int_lt); tcase_add_test(ltgt_case, int_le); tcase_add_test(ltgt_case, int_gt); tcase_add_test(ltgt_case, int_ge); suite_add_tcase(suite, ltgt_case); return suite; }
String Assertions
I’ve omitted the suite creation here for brevity.
#include <check.h> START_TEST (str_eq) { ck_assert_str_eq("Hello World", "Hello World"); } END_TEST START_TEST (str_ne) { ck_assert_str_ne("Hello Check", "Hello World"); } END_TEST START_TEST (str_lt) { ck_assert_str_lt("Hello Check", "Hello World"); } END_TEST START_TEST (str_le) { ck_assert_str_le("Hello Vorld", "Hello World"); ck_assert_str_le("Hello World", "Hello World"); } END_TEST START_TEST (str_gt) { ck_assert_str_gt("Hello Xorld", "Hello World"); } END_TEST START_TEST (str_ge) { ck_assert_str_ge("Hello World", "Hello World"); ck_assert_str_ge("Hello Xorld", "Hello World"); } END_TEST
General Functions
Again, suite omitted for brevity.
#include <check.h> #include <stdbool.h> START_TEST (general_assertion) { ck_assert(true == true); ck_assert(1 == 2 - 1); ck_assert(strcmp("hello", "Hello") > 0); } END_TEST START_TEST (pointer_equality) { char *p1 = "Hello World"; char *p2 = p1; ck_assert_ptr_eq(p1, p2); } END_TEST START_TEST (pointer_inequality) { char *p1 = "Hello World"; char *p2 = p1; p2++; ck_assert_ptr_ne(p1, p2); } END_TEST START_TEST (general_assertion_with_message) { ck_assert_msg(true == 0, "True is not 0"); } END_TEST START_TEST (abort_test) { ck_abort(); } END_TEST START_TEST (abort_test_with_message) { ck_abort_msg("I fail, and tell you that I do"); } END_TEST
Reporting
If you don’t want just the default textual output, setting the environment variable CK_XML_LOG_FILE_NAME
may prove quite helpful. For instance, the xUnit plugin for Jenkins will be able to publish the results.
stage('Test') { env.CK_XML_LOG_FILE_NAME = 'TEST-results.xml' sh './run_tests' step([$class: 'XUnitPublisher', tools: [ [$class: 'CheckType', pattern: '**/TEST-*.xml', stopProcessingIfError: true] ]]) }