C Testing
Pragmatic workflow for reliable C tests and bug-finding.
When to activate
- Adding unit tests for C functions
- Building a small test harness around a module
- Debugging failing tests or memory corruption
- Enabling sanitizers or fuzzing to reproduce crashes
Core rules
- Keep unit tests deterministic and isolated.
- Avoid real network/time in unit tests.
- Run ASan/UBSan in CI for memory and UB signal.
- Reproduce failures in the smallest possible command first.
- Do not hide memory/UB bugs behind test-only flags, retries, or inflated timeouts.
- Pair with
test-driven-developmentwhen implementing persistent code or bug fixes test-first. - Pair with
testing-reliabilityfor fixture/timing anti-patterns andsystematic-debuggingwhen the root cause is unclear.
Recommended workflow
Phase 1 — Reproduce with smallest scope
- Run the single failing test first (
ctest -R ...or direct binary invocation). - Capture exact command, seed/input, and environment variables.
- Eliminate unrelated test noise before debugging.
Phase 2 — Strengthen harness determinism
- Keep each test independent (no shared mutable global state).
- Use explicit fixtures/setup-teardown for temp files and state reset.
- Prefer table-driven tests for parsers and boundary-heavy functions.
Phase 3 — Sanitizer-first diagnosis
- Run AddressSanitizer for memory corruption/UAF/OOB.
- Run UndefinedBehaviorSanitizer for integer/shift/null/alignment UB.
- Use stack-symbolized reports before stepping into debugger.
Phase 4 — CTest execution strategy
- Label tests (
unit,integration,slow,flaky) and run by label. - Use
--output-on-failureand--rerun-failedin local loops. - Add per-test
TIMEOUTto avoid hanging pipelines.
Phase 5 — Fuzzing escalation
- Add libFuzzer target for parser/decoder/validator style APIs.
- Seed corpus with valid and invalid minimal inputs.
- Keep fuzz target stateless, deterministic, and side-effect free.
Fast triage checklist
- Single failing test reproduced in isolation.
- Failure reproduced under sanitizer build (if memory/UB suspected).
- Backtrace/symbolization points to root cause function.
- Regression test added for the fixed bug.
- Full suite rerun (or label-targeted suite if justified) with no new failures.
Resources
Load on demand:
references/harness.md— harness structure, assertions, Unity/cmocka optionsreferences/cmake-ctest.md— CMake/CTest patterns, labels, sanitizer presets, MinGW cross-compilereferences/sanitizers-fuzzing.md— ASan/UBSan usage and a minimal fuzz target outlinereferences/debugging.md— gdb/lldb, Valgrind, MinGW objdump/nm, MSVC dumpbin/WinDbg, ASan env vars