Defines unit-test boundaries and fixture practices that produce fast, deterministic evidence for domain behavior without over-mocking collaborators or turning implementation details into a frozen API.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Unit-test deterministic policy and state transitions through public module interfaces. Use small builders with explicit relevant values, real value objects, controlled clocks and randomness, and fakes only at true I/O boundaries.
Scope
- Test selection, unit boundary, fixtures, builders, doubles, time/randomness, errors, properties, mutation confidence, naming, and CI feedback.
- Domain and application code whose dependencies can be controlled in process.
- Relationship to integration and contract tests.
Outside this block
- Replacing database, transport, browser, or provider integration tests.
- Pursuing line coverage as the primary quality objective.
Contract
- Each test names one observable behavior, arranges only relevant state, invokes a public boundary, and asserts stable outputs or state.
- Fixtures default to valid minimal objects but require explicit values for fields material to the behavior.
- Clocks, IDs, and randomness are injected or captured so failures reproduce.
- Mocks verify protocol only where the interaction itself is the contract; otherwise fakes or output assertions are preferred.
- Error tests assert domain code and safe context rather than brittle full messages unless wording is public API.
- Bug fixes add the smallest failing test at the layer where the defect could be prevented.
Implementation guidance
- Create typed fixture builders with named scenario presets and no hidden network/database calls.
- Use table tests for boundary partitions and property tests for algebraic invariants when appropriate.
- Run mutation testing or targeted fault injection periodically to discover assertion-free coverage.
- Keep shared fixtures local to one domain and version public contract fixtures deliberately.
Failure handling and safeguards
- A flaky unit test is quarantined only with an owner and expiry; its protected behavior needs replacement evidence.
- If a test needs extensive mocking of internals, reconsider the module boundary or move the behavior to an integration test.
- If a global clock or random seed leaks between tests, isolate it rather than relying on execution order.
Verification and operations
- Track duration distribution, flake rate, retry-hidden failures, changed-code test coverage, mutation score for critical modules, and escaped defects by missing test layer.
- Keep a fast presubmit tier and a complete unit tier with explicit budgets.
- Review fixture growth and duplicated setup as design signals.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.
References
- No external normative source is required; this package defines a project decision.