tdd-patterns
Use this when running the multi-agent SKELETON→RED→GREEN→REFACTOR TDD cycle, designing interface-driven tests against compilable stubs, or coordinating mock-based TDD between code-generator and test-s
Files2
View on GitHubSKILL.mdskills/tdd-patterns/SKILL.md
GitHubtdd-patterns (v1.1.0)
Scope
Defines the language-neutral SKELETON→RED→GREEN→REFACTOR cycle and the agent coordination around it. Language-specific syntax (test-runner conventions, mock libraries, sentinel-discrimination idioms) lives in language-pack siblings: go-tdd-patterns, python-tdd-patterns.
The cycle in the agent system
The pipeline runs TDD as a four-step cycle per package or feature:
- code-generator (SKELETON) writes compilable stubs — interfaces, struct shapes, constructors that return real instances, method bodies that explicitly signal "not implemented" via the language-native idiom. Tests can import the package and reference its surface.
- test-spec-generator (RED) writes failing tests against the skeleton. Each test asserts at least one observable outcome that the skeleton cannot satisfy. Tests define WHAT the implementation must do — they are the specification.
- code-generator (GREEN) reads ALL test files first, then writes the minimum impl to make them pass. It does not add behavior that isn't tested.
- refactoring-agent (REFACTOR) improves shape without breaking the GREEN state. Tests stay green throughout.
SKELETON rules (language-neutral)
- All exported interfaces / Protocols / abstract bases fully defined — every method signature with parameter and return types.
- Structs / dataclasses have correct fields and serialization annotations.
- Constructors return real instances (not nil/None).
- Method stubs explicitly signal "not implemented" via the language-native idiom (sentinel error, raised exception, etc. — see language packs).
- Package structure matches the design exactly.
RED rules (language-neutral)
- Assertion-first: start with what you want to verify, work backward to setup.
- Behavior, not implementation: tests should still pass after a refactor that doesn't change observable behavior.
- Error paths matter: every error condition the impl should handle gets a test that exercises it.
- Typed discrimination: when a test cares about a specific failure mode, it must check via the language's typed-error mechanism (sentinel identity, exception class), not a substring of the error message.
GREEN rules (language-neutral)
- Read every test file in the package before writing impl code.
- Write the MINIMUM code to make tests pass — do not add features no test expects.
- If a test expects a specific failure type, return that exact type.
- After each significant change, run the active language adapter's test command (
toolchain.testfrom the package manifest).
REFACTOR rules (language-neutral)
- Tests must remain green throughout. If you must change a test, justify it.
- Refactor for: clarity, extracted abstractions where 3+ duplicates exist, naming alignment with sibling packages.
- Do NOT add new untested behavior in the refactor pass.
Verification cycle
After GREEN, the phase lead runs the active toolchain's test command. Outcomes:
- ALL PASS → proceed to next package or to refactor.
- SOME FAIL → code-generator gets failure output, fixes, re-verify (max 2 retries per package).
- COMPILATION ERROR / IMPORT ERROR → code-generator fixes, re-verify.
After 2 failures, the package is flagged BLOCKED in the run manifest; pipeline continues with other packages in parallel.
Anti-patterns (language-neutral)
- Weak assertions — tests that pass on the skeleton (no real assertion). Always assert at least one observable outcome.
- Testing implementation details — exact-equality on mock arguments breaks any refactor. Assert behavioral properties.
- Skipping error-path tests — every documented error must be exercised in at least one test.
Coverage strategy
- Every public method on application services (happy path + error paths) gets a RED test.
- Every domain constructor and validation method gets a RED test.
- Tenant / scoping isolation in repositories where applicable.
- Wire-protocol publishing on state changes.
- Target ≥60-70% coverage in the RED phase; remaining 15-25% to reach the package's coverage gate is filled by unit-test-agent in the cross-cutting testing phase.
Language realizations
go-tdd-patterns— Go realization (test runner setup, mock controllers, table-driven subtests, sentinel-discrimination idiom, compile-time interface assertions).python-tdd-patterns— Python realization (test framework setup, async test markers, Protocol-spec mocks, parametrize tables, exception-raising assertions, fixture composition).
Cross-references
- shared-core
decision-logging— agent cycle steps logged as lifecycle entries - shared-core
review-fix-protocol— what happens when verification fails - shared-core
spec-driven-development— how TPRD §7 symbols map to tests