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]
]])
}