--- name: tdd description: Build or fix behavior test-first through red-green-refactor. Use when the user requests TDD or test-first development, not merely any integration-test task. --- # Test-Driven Development TDD is the red → green → refactor loop. Use behavior-level tests to guide small changes; choose checks proportional to the task. When exploring the codebase, read `CONTEXT.md` (if it exists) so test names and interface vocabulary match the project's domain language, and respect ADRs in the area you're touching. ## What a good test is Tests verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. A good test reads like a specification — "user can checkout with valid cart" tells you exactly what capability exists — and survives refactors because it doesn't care about internal structure. See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines. ## Seams — where tests go A **seam** is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals. Reuse established test boundaries and any seams already agreed with the user. Choose a seam that exercises the actual behavior, including persistence or integration contracts where those are the subject of the test. State a new choice briefly; ask only if it introduces a consequential design trade-off that cannot be inferred from the request and code. Prioritize critical paths, failure modes, and complex logic; do not block routine tests on repeated seam approval. ## Anti-patterns - **Implementation-coupled** — mocks internal collaborators, tests private methods, or verifies through a side channel (querying the database instead of using the interface). The tell: the test breaks when you refactor but behavior hasn't changed. - **Tautological** — the assertion recomputes the expected value the way the code does (`expect(add(a, b)).toBe(a + b)`, a snapshot derived by hand the same way, a constant asserted equal to itself), so it passes by construction and can never disagree with the code. Expected values must come from an independent source of truth — a known-good literal, a worked example, the spec. - **Horizontal slicing** — writing all tests first, then all implementation. Bulk tests verify _imagined_ behavior: you test the _shape_ of things rather than user-facing behavior, the tests go insensitive to real changes, and you commit to test structure before understanding the implementation. Work in **vertical slices** instead — one test → one implementation → repeat, each test a **tracer bullet** that responds to what the last cycle taught you. ## Rules of the loop - **Red before green.** Write the failing test first, then only enough code to pass it. Don't anticipate future tests or add speculative features. - **One slice at a time.** One seam, one test, one minimal implementation per cycle. - **Refactor while green.** Simplify the changed code and tests without changing behavior, then rerun the checks. Keep unrelated redesign outside the task.