Tdd
Skill rynhardt-potgieter/sprint_workflow/plugins/sprint-workflow/skills/tdd
Test-driven development loop — red, green, refactor. Use this skill when implementing any feature with clear acceptance criteria, when fixing bugs (regression test first), and inside /sprint-start Phase 1 + Phase 2. Defines cycle length, when NOT to TDD, and integration with sprint quality gates.From its SKILL.md
npx -y skills add rynhardt-potgieter/sprint_workflow --skill tddAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.4 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Test-Driven Development
The discipline of writing the test before the implementation. The test defines what success looks like and prevents over-engineering. The implementation is then the smallest change that makes the test pass.
This skill is read by test-writer (always) and by backend-dev / frontend-dev when a task's acceptance criteria are well-defined enough to test first.
When to TDD
| Task type | TDD? | Rationale |
|---|---|---|
| Pure logic (calculations, parsing, state machines) | Yes | Tests are cheap, behaviour is precise |
| API endpoints with defined request/response | Yes | Spec tells you the test |
| Bug fixes | Yes — always | Regression test must fail without the fix |
| MediatR command/query handlers | Yes | Inputs and outputs are explicit |
| React components with defined props/output | Yes | Testing-Library makes this fast |
| Pure UI styling, layout, animation | No | Visual regression / Playwright instead |
| Exploratory spikes / prototypes | No | Throwaway code; tests slow exploration |
| Generated code (migrations, scaffolds) | No | Test the migration, not the generator |
| Pure plumbing (DI registration, wiring) | No | Integration tests cover this |
When in doubt, TDD. The cost of writing a test first is low; the cost of over-engineered untested code is high.
The Loop
Red — write a failing test
- Read the acceptance criterion you're implementing. Pick one behaviour.
- Write a test that asserts the behaviour. The test must:
- Reference the function / endpoint / component you're about to write (it doesn't exist yet, or doesn't behave correctly yet)
- Have a clear assertion (one concept per test — see
code-standards) - Use the project's existing test framework and patterns
- Run the test. Confirm it fails. Read the failure message — it must fail for the right reason (not "import error", "syntax error", "fixture not found"). If it fails for the wrong reason, fix that first.
A test that fails for the wrong reason is not a red test.
Green — make it pass
- Write the smallest code change that makes the test pass.
- No extra features. No "while I'm here" fixes. No defensive code for cases the test doesn't cover.
- Run the test. Confirm it passes.
- Run the full test suite for the affected area. Confirm nothing else broke.
If you can't make it pass with a small change, the test was probably wrong. Stop and rewrite the test before the implementation.
Refactor — clean up
With the test as a safety net:
- Rename anything unclear
- Extract obvious duplication
- Improve naming, ordering, formatting
- Run the tests after every refactor — they must stay green
Refactoring without tests is editing. Refactoring with tests is safe.
Cycle Length
A red-green-refactor cycle should take minutes, not hours.
- If a single test takes more than 30 minutes to make pass, the test is probably testing too much. Split it.
- If you've been writing implementation for an hour without seeing green, you've left the loop. Stop, get back to a passing state (revert if needed), and write a smaller test.
Small cycles compound. Long cycles produce untested code with the test added at the end as theatre.
Bug Fixes (Mandatory TDD)
For any bug fix:
- Write a regression test that reproduces the bug
- Run it. Confirm it fails — and fails with the same symptom the user reported
- Apply the fix from the
diagnoseskill - Run the regression test. Confirm it passes.
- Run the full suite. Confirm no other test broke.
The regression test is the artifact that prevents the bug from recurring. A bug fix without one is incomplete.
Anti-Patterns
| Anti-pattern | Better |
|---|---|
| Writing 10 tests, then 10 implementations | One test, one implementation, one cycle |
| Asserting "no exception thrown" with no behaviour check | Assert the actual outcome (return value, side effect, state) |
| Testing the test framework or language internals | Test your code's behaviour |
| Mocking everything until the test asserts nothing real | Mock external boundaries only (DB, HTTP, time); use the real thing for internal collaborators |
| Writing the test after the implementation, then claiming TDD | Order matters. The test must fail before the code is written. |
| Skipping refactor because "tests pass, ship it" | Tests are the licence to refactor; using them to avoid refactoring is waste |
| TDD-ing UI styling | Use visual regression / Playwright; TDD doesn't fit pixel-level work |
Integration with Sprint Workflow
Phase 1: Implementation
When acceptance criteria are testable and the task is on the TDD list above:
- The implementing agent (
backend-dev/frontend-dev) writes the test first, then the implementation - The agent commits red and green together (or as a single logical unit) — not in separate commits, since the red test is incomplete
Phase 2: Test Writer
test-writer augments TDD tests with:
- Edge cases not covered by the AC tests (empty collections, boundary values, error paths)
- Integration tests across module boundaries
- Snapshot tests where output format is a contract
test-writer does not duplicate the AC tests — it fills the gaps.
Phase 3: QA
qa-agent (or Codex adversarial review) verifies:
- Every acceptance criterion has at least one test asserting it
- Bug fixes have regression tests
- Tests fail without the implementation (spot-check by reverting one change and running the test)
A task that passes all builds but has no test for its AC fails QA.
Per-Stack Notes
The TDD loop is the same. The mechanics differ:
- .NET (xUnit):
[Fact]/[Theory], in-memoryDbContext,Moqfor boundaries. Seedotnet-api. - React (Vitest):
@testing-library/react,userEventfor interactions,vi.fn()for mocks. Seereact-typescript. - Rust:
#[test]for unit,tests/for integration,instafor snapshots,tempdirfor filesystem. Seerust-testing. - API endpoints: contract test via the response wrapper / status code / RFC 7807 shape. See
api-design.
Read the relevant per-stack skill before writing the first test.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 4 of the 12 instructions most tdd skills give in ~1.4k tokens
Counted across 439 of the 443 authors here whose files we hold, read 2026-08-07
- Write minimal code to pass the testin 304 of 439, across 222 files
- Write a failing test firstin 174 of 439, across 111 files
- Refactor code only after tests passhere, and in 172 of 439, across 102 files
- Watch the test fail before writing codein 145 of 439, across 97 files
- Test one behavior per testhere, and in 108 of 439, across 46 files
- Refactor code while keeping tests greenin 100 of 439, across 88 files
- Delete code written before testsin 99 of 439, across 55 files
- Run tests after each refactor stepin 88 of 439, across 57 files
- Confirm the test fails for the right reasonhere, and in 66 of 439, across 62 files
- Use real code instead of mocks unless unavoidablein 60 of 439, across 17 files
- Reproduce bugs with a test before fixingin 53 of 439, across 36 files
- Write tests before implementationhere, and in 51 of 439, across 43 files
Said here and by no other author read
- commit red and green tests together
- read the relevant stack skill first
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.