TDD is the red → green loop. This skill is the reference for making that loop produce tests worth keeping: what a good test is, where tests go, what the anti-patterns are, what the rules of the loop are. Every section applies in every cycle—consult them before and during the loop, not after.
When exploring the codebase, read GLOSSARY.md(if it exists), keep test names and interface vocabulary consistent with the project's domain language, and respect the ADRs for the area you are touching.
What a Good Test Is
A test verifies behavior through the public interface, not implementation details. The code can change completely; the tests should not. A good test reads like a specification—"a user can check out with a valid cart" tells you precisely what capability exists—and because it does not care about internal structure, it survives refactoring.
For examples see tests.md, for mocking guidelines see mocking.md。
Seams—Where Tests Go
A **seam** is the public boundary where you test: the interface where behavior is observed without reaching inside. Tests live at the seam, never against internals.
Test only at pre-agreed seams. Before writing any test, write down the seam to be tested and confirm it with the user. No test is written on an unconfirmed seam. You cannot test everything—agreeing on seams in advance is precisely how test effort lands on critical paths and complex logic rather than every edge case.
Ask: "What is the public interface, and which seams should we test?" Attach a one-line note to each proposed seam stating what it can catch and what it will miss.
When the shape of the interface itself is in question—how deep a module should be, where the seam should be, what the interface should expose—invoke the Skill tool with "codebase-design" for the vocabulary. It is the shared source of the words module, interface, depth, seam, adapter, leverage, locality—a reference to consult, not a session to run.
Anti-Patterns
- Implementation-coupled — mocking internal collaborators, testing private methods, or verifying through a back channel (querying the database instead of using the interface). Telltale sign: behavior did not change during refactoring, but the test broke.
- Tautological — the assertion recomputes the expected value the same way the code does (
expect(add(a, b)).toBe(a + b), a snapshot hand-derived the same way, asserting a constant equals itself), so it passes constructively and can never disagree with the code. The expected value must come from an independent source of truth—a known-correct literal, a hand-computed example, a specification. - Horizontal slicing — writing all the tests first, then all the implementation. Batches of tests verifyimaginedbehavior: you test theshapeof things rather than user-facing behavior, tests become insensitive to real changes, and you lock in test structure before understanding the implementation. Usevertical slicinginstead—one test → one implementation → repeat, with each test atracer bullet, respond to what the previous cycle taught you.
The rules of the cycle
- Red first, then green. Write the failing test first, then write only the code that is just enough to pass it. Do not anticipate future tests, and do not add speculative features.
- One slice at a time. One seam, one test, one minimal implementation per cycle.
- Refactoring is not part of the cycle. It belongs to the review phase (see
code-reviewskill), not to the red → green implementation cycle.