CMocka

Language: C

Testing

CMocka was developed as a modern alternative to other C unit testing frameworks. It emphasizes simplicity, minimal dependencies, and provides support for mock objects, test fixtures, and assertions to ensure reliable C code testing.

CMocka is a lightweight, modern unit testing framework for C. It provides a simple API for writing unit tests, mocking functions, and verifying behavior in C programs.

Installation

linux: sudo apt install cmocka cmocka-doc
mac: brew install cmocka
windows: Build from source using CMake or use vcpkg: `vcpkg install cmocka`

Usage

CMocka allows you to define test functions, use setup and teardown functions for test fixtures, perform assertions, and run tests via a test runner. It supports mocking to replace functions and verify interactions.

Simple test case

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

int add(int a, int b) { return a + b; }

static void test_add(void **state) {
    assert_int_equal(add(2, 3), 5);
}

int main(void) {
    const struct CMUnitTest tests[] = { cmocka_unit_test(test_add) };
    return cmocka_run_group_tests(tests, NULL, NULL);
}

Defines a simple test for an `add` function and runs it using CMocka's test runner.

Using setup and teardown

static int *ptr;

static int setup(void **state) { ptr = malloc(sizeof(int)); *ptr = 42; return 0; }
static int teardown(void **state) { free(ptr); return 0; }

static void test_example(void **state) { assert_int_equal(*ptr, 42); }

Demonstrates initializing and cleaning resources before and after a test using setup and teardown functions.

Mocking functions

// Use cmocka's mock() and expect_value() functions to replace and verify calls to other functions in the tested code.

Enables unit testing of components that depend on external functions by mocking them.

Grouping multiple test cases

static void test_subtract(void **state) { assert_int_equal(5 - 3, 2); }
const struct CMUnitTest tests[] = {
    cmocka_unit_test(test_add),
    cmocka_unit_test(test_subtract)
};

Groups multiple tests into a single test suite for organized execution.

Error Handling

Assertion failure: Check the assertion message to identify why the test failed and debug the function accordingly.
Segmentation fault: Ensure proper memory allocation and pointer usage in tests and tested functions.

Best Practices

Use setup and teardown functions to handle resource allocation and cleanup.

Keep tests independent to avoid side effects.

Use meaningful assertions for clarity.

Leverage mocks for testing functions with external dependencies.

Run tests frequently to catch regressions early.