| name | tdd |
| description | Choose an appropriate test level and use red-green-refactor when test-first work is requested. Use when the user asks for TDD, red-green-refactor, test-first development, integration tests, or help deciding coverage. Prefer integration tests for meaningful behavior across boundaries, unit tests for nontrivial isolated logic requiring little or no mocking, and no new test for trivial behavior adequately covered by types or existing tests. |
Pragmatic Test Strategy and TDD
Principle
Tests are maintenance code. Add a test when it meaningfully protects observable behavior from regression; do not create tests merely because code changed.
Prefer tests through public interfaces. A useful test should survive internal refactoring and fail when caller-visible behavior breaks.
Choose the Test Level First
Before writing a test, choose one of these outcomes and state the reason briefly.
No New Test
Skip a new test when the changed behavior is trivial and another mechanism already provides enough confidence, for example:
- Straight-line wiring, a simple getter, or a mechanical mapping with no meaningful branch or invariant.
- A constraint enforced completely by the type system, schema, compiler, or existing test.
- The exact outcome is already exercised by an existing integration test.
- The proposed test would only restate the implementation or assert collaborator calls.
Still run the relevant existing checks. Do not use “trivial” to skip coverage for permissions, money, persistence, concurrency, data loss, security, or other high-risk behavior.
Unit Test
Use a unit test for nontrivial, isolated logic when:
- The subject is deterministic and has a small public interface.
- Its rules, state transitions, parsing, calculation, or edge cases deserve focused coverage.
- It requires little or no mocking and no complex fixture graph.
If isolating the subject requires several mocked internal collaborators or assertions about call order, use an integration test instead.
Integration Test
Prefer an integration test when meaningful behavior crosses boundaries such as:
- Multiple application modules or services.
- Persistence, serialization, queues, events, or external adapters.
- Authentication, authorization, workflows, or dependency layers.
- A public API whose contract matters more than its internal decomposition.
Use real local implementations, test databases, or Testcontainers where practical. Fake only genuinely external or nondeterministic boundaries. See mocking.md.
See tests.md for examples of each decision.
TDD Workflow
Use red-green-refactor when the user explicitly requests test-first development or repository guidance requires it.
- Select one meaningful observable behavior.
- Write one test at the chosen level and confirm it fails for the intended reason.
- Implement the minimum behavior needed to make it pass.
- Refactor only while green, then run the relevant tests again.
- Repeat vertically for the next valuable behavior.
Do not write the entire test suite before implementation. Let each completed slice inform the next one.
Planning
- Inspect existing coverage and repository test conventions before adding a new test level.
- Prefer the smallest test that proves meaningful behavior, not the smallest test by isolation.
- Ask the user only when test scope materially changes delivery cost or risk and cannot be inferred from repository guidance.
- Design public interfaces for testability when needed; see interface-design.md and deep-modules.md.
- Use refactoring.md after reaching green.
Checklist