Test Organization
April 27, 2026 ยท View on GitHub
This project keeps production modules behind normal module boundaries, while test files are compiled as separate test roots from build.zig.
Goals
- Keep production code free of inline
testblocks. - Keep test-only fixtures outside
src/. - Run each test file as an independent Zig test artifact.
- Preserve the exact test descriptions from
mainwhen refactoring behavior. - Prefer public behavior-oriented module boundaries over test-only access shims.
Directory Layout
src/
root.zig # public package surface
... # production modules only
tests/
*_test.zig # behavior and regression tests
support/
fixtures.zig # test-only builders and file helpers
Test files should be grouped by product area or workflow, not by implementation detail. Use names such as api_http_test.zig, registry_import_test.zig, tui_table_test.zig, or workflows_live_test.zig.
Build Integration
build.zig owns the test suite with an explicit test_files array. For each entry, it creates a separate b.addTest artifact and injects the codex_auth package import.
This keeps failures localized to the test file that owns them and avoids a large aggregate tests/root.zig importing everything manually.
A small library compile test may be included to validate the package surface with std.testing.refAllDecls.
Production/Test Boundary
Production modules must not import tests/ or tests/support/.
Avoid test_api or other test-only public namespaces in src/. If a rule is important enough to test directly, prefer one of these options:
- Test it through a public behavior or workflow.
- Extract it into a focused production module with a normal public API.
- Make the helper public only when it is a stable, useful module boundary.
Private implementation details that are not stable behavior should not be tested directly.
Fixtures
Fixtures belong under tests/support/. Import them with a relative path from tests:
const fixtures = @import("support/fixtures.zig");
Do not expose fixtures from src/root.zig.
Test Descriptions
When refactoring, test descriptions must remain compatible with main. This is part of the compatibility contract. A refactor is acceptable only when the set of test descriptions remains unchanged unless the behavior itself intentionally changes.
Validation Checklist
After changing .zig files, run these from an isolated /tmp/<task-name> directory with isolated HOME and CODEX_HOME:
zig fmt $(find /path/to/repo -name '*.zig' -type f | sort)
zig build --build-file /path/to/repo/build.zig --cache-dir /tmp/<task-name>/cache test
zig build --build-file /path/to/repo/build.zig --cache-dir /tmp/<task-name>/cache run -- list
git diff --check
Also verify:
rg '^test "' src
rg 'test_api|src/testing|testing\.fixtures' src tests
The first command should return no source inline tests. The second command should return no test_api or production fixture exports.