| name | test-driven-development |
| description | Use when implementing any feature or bugfix, before writing implementation code |
| skill_type | rigid |
Test-Driven Development
TDD is the red → green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop. Every section applies on every cycle — consult them before and during the loop, not after.
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.
Resolve the Test Command
Before RED/GREEN verification, resolve the project's test command in this order:
- Read
.superharness/spec/testing/index.md when it exists.
- Otherwise inspect the repository manifest and lockfile:
package.json, Python manifests, pom.xml, Gradle files, or Package.swift.
- Prefer the framework's single-file or single-test invocation for the red-green loop.
- Record a newly discovered command in
.superharness/spec/testing/index.md when that project convention allows updating the specification.
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 for examples and 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.
Test only at pre-agreed seams. No test is written at an unconfirmed seam. You can't test everything — agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case.
For Full work, the approved plan task's Public Seams are already confirmed. Do not prompt the user again.
For Lite work, read contract.md Test Seams first; ask the user only when the relevant seam is missing or unclear.
Verification mode — which slices get a test
Behavior slices carry a verification mode decided at plan time. Only tested slices enter the red-green loop. A verified slice is covered by its declared gate — run or confirm that gate's evidence; do not write a dedicated test for it. Never downgrade a tested slice on your own: when a slice looks misclassified, stop and return NEEDS_CONTEXT naming the slice instead of silently deviating.
When no mode is declared (legacy plans, direct invocations), treat a slice as tested only when it has an independent expectation source, meaningful error space (branching, boundaries, transformation, state transitions, protocol compatibility), and a failure observable at a public seam; otherwise name the gate that covers it.
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.
- Low-signal — asserts static copy, fixed strings, constants, or framework-guaranteed behavior. The test can fail, but only when someone edits that value on purpose: requirement change and test change are always the same edit, so it catches zero unintended regressions. Distinct from tautological, which cannot fail by construction. Copy that is itself a contract is worth testing: legal, price, or payment wording, accessibility names, i18n key mappings, state-dependent copy, and prompt or skill text whose content is executable behavior.
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.
- Refactoring is not part of the loop. It belongs to the review stage after the red → green implementation cycle.
Verification checklist