Frontend Labs
⋯

15. A minimal test harness for C

C has no built-in test framework; most real projects either pull in something like Unity/Check/CMocka, or — for smaller libraries — write 30 lines of macros once and reuse them forever. Here's that 30 lines, because understanding it demystifies every "real" framework:

// test.h
#ifndef TEST_H
#define TEST_H
#include <stdio.h>

static int tests_run = 0, tests_failed = 0;

#define ASSERT_EQ(actual, expected) do {                                    \
    tests_run++;                                                            \
    if ((actual) != (expected)) {                                           \
        tests_failed++;                                                     \
        fprintf(stderr, "FAIL %s:%d: expected %ld, got %ld\n",              \
                __FILE__, __LINE__, (long)(expected), (long)(actual));      \
    }                                                                        \
} while (0)

#define TEST_SUMMARY() do {                                                  \
    printf("%d/%d tests passed\n", tests_run - tests_failed, tests_run);     \
    return tests_failed ? 1 : 0;                                             \
} while (0)

#endif
// test_add.c
#include "test.h"

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

int main(void) {
    ASSERT_EQ(add(2, 2), 4);
    ASSERT_EQ(add(-1, 1), 0);
    ASSERT_EQ(add(0, 0), 1);   // intentionally wrong, to see a FAIL line
    TEST_SUMMARY();
}

do { ... } while (0) wrapping a multi-statement macro is the standard trick that makes ASSERT_EQ(x, y); behave like a single statement inside an if without a trailing-semicolon or dangling-else bug — you'll see this exact pattern in nearly every C macro that expands to more than one expression.


Generated from real-life-c-guide.md · 8 Oct 2026 16:36