Skip to main content

tdd

Test-driven development via the red-green-refactor loop using vertical slices (one test → one implementation at a time). Tests verify behavior through public interfaces, not implementation details. Use when user wants to build a feature or fix a bug test-first, says "TDD", "red-green-refactor", "test-first", "write tests first", asks for integration tests, or invokes `/tdd`.

Quellinformationen

Repository
orakitine/toolbox
Letzte Quellaktivität
22. Juni 2026 um 19:27
Erkannte Sprache von SKILL.md
Englisch
Sterne
0
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
8 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
tdd
description
Test-driven development via the red-green-refactor loop using vertical slices (one test → one implementation at a time). Tests verify behavior through public interfaces, not implementation details. Use when user wants to build a feature or fix a bug test-first, says "TDD", "red-green-refactor", "test-first", "write tests first", asks for integration tests, or invokes `/tdd`.
# Purpose Drive feature development and bug fixes through tight red-green-refactor cycles, one behavior at a time. Tests verify observable behavior through public interfaces so they survive internal refactors. Vertical slices (tracer bullets) replace the "write all tests, then all code" anti-pattern because tests written in bulk inevitably test imagined behavior — not actual behavior. ## Philosophy **Tests verify behavior through public interfaces, not implementation details.** Code can change entirely; tests shouldn't. - **Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_. A good test reads like a specification — "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure. - **Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior. **Anti-pattern: horizontal slices.** DO NOT write all tests first, then all implementation. That treats RED as "write all tests" and GREEN as "write all code." It produces crap tests because: - Tests written in bulk test _imagined_ behavior, not _actual_ behavior - You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior - Tests become insensitive to real changes — they pass when behavior breaks, fail when behavior is fine - You outrun your headlights, committing to test structure before understanding the implementation **Correct approach: vertical slices via tracer bullets.** One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. ``` WRONG (horizontal): RED: test1, test2, test3, test4, test5 GREEN: impl1, impl2, impl3, impl4, impl5 RIGHT (vertical): RED→GREEN: test1→impl1 RED→GREEN: test2→impl2 RED→GREEN: test3→impl3 ... ``` ## Workflow 1. **Plan with the user before writing any code** - Explore the codebase. Use the project's domain glossary so test names and interface vocabulary match the project's language. Respect ADRs in the area you're touching. - Confirm with the user what interface changes are needed - Confirm with the user which behaviors to test, and prioritize them — you can't test everything, so focus on critical paths and complex logic, not every possible edge case - Identify opportunities for **deep modules** (small interface, deep implementation) — see `./references/deep-modules.md` - Design interfaces for **testability** (accept dependencies, return results, small surface) — see `./references/interface-design.md` - List behaviors to test (not implementation steps) - Get user approval on the plan before proceeding - Example: User asks to add a checkout flow → ask "What should the public `checkout()` interface look like? Which behaviors matter most — happy path, invalid cart, payment failure, partial refund?" Get explicit prioritization before any test is written. 2. **Fire the tracer bullet** - Write ONE test that confirms ONE thing about the system - RED: test fails (confirm it fails for the right reason — not a syntax error) - GREEN: write the minimum code to make it pass - This proves the path works end-to-end before you build more on top of it - Example: ``` RED: test("checkout with valid cart returns confirmed status") → fails (no checkout fn) GREEN: implement minimal checkout() returning { status: "confirmed" } → test passes ``` 3. **Loop one behavior at a time** - For each remaining behavior, run RED → GREEN - Rules: - One test at a time - Only enough code to pass the current test - Do NOT anticipate future tests - Keep tests focused on observable behavior through the public interface - After each GREEN, run the **per-cycle checklist**: - [ ] Test describes behavior, not implementation - [ ] Test uses public interface only - [ ] Test would survive an internal refactor - [ ] Code is minimal for this test - [ ] No speculative features added - IF: the test breaks when you rename an internal function but behavior is unchanged → THEN the test is coupled to implementation; rewrite it against the public interface (see `./references/tests.md` for good/bad examples) - IF: the behavior crosses a system boundary (external API, database, time, randomness, filesystem) → THEN mock at that boundary only — never mock internal collaborators (see `./references/mocking.md`) - Example: Next behavior is "checkout with empty cart returns error" → write that test alone, watch it fail, add the minimal guard clause, watch it pass, then run the checklist. 4. **Refactor only while GREEN** - Never refactor while RED. Get to GREEN first. - After all tests for the current slice pass, look for refactor candidates: duplication, long methods, shallow modules, feature envy, primitive obsession, and existing code the new code reveals as problematic (see `./references/refactoring.md`) - Apply changes: - Extract duplication - Deepen modules (move complexity behind simple interfaces) - Apply SOLID principles where natural - Consider what the new code reveals about existing code - Run tests after EACH refactor step. If anything goes red, undo or fix immediately before the next step. - Example: After three checkout tests are green you notice cart-total math repeated in two places → extract `calculateTotal(cart)`, run tests, all green → continue. 5. **Return to the loop or finish** - IF: more prioritized behaviors remain → return to step 3 - IF: all prioritized behaviors are covered and refactor pass is clean → summarize what was built, which behaviors are covered, and any deferred behaviors the user explicitly chose not to test - Example: "Checkout flow done. Covered: valid cart, empty cart, payment failure. Deferred per your call: partial refund (edge case, low priority)." ## References ### Good vs. bad tests, with examples - IF: deciding whether a test is well-formed, debugging a test that breaks on refactor, or unsure what to assert - THEN: Read `./references/tests.md` - EXAMPLES: - "is this test testing implementation or behavior?" - "my tests keep breaking when I rename things" - "what should I assert here?" ### Mocking and system boundaries - IF: about to mock something, designing an external integration, or wondering if a dependency should be injected - THEN: Read `./references/mocking.md` - EXAMPLES: - "should I mock the database?" - "how do I test this Stripe integration?" - "this function is hard to mock — what do I change?" ### Interface design for testability - IF: designing a new function or module, or an existing one is painful to test - THEN: Read `./references/interface-design.md` - EXAMPLES: - "this function takes too many params to test" - "how should I shape this API?" - "the test setup is enormous — what's wrong with the interface?" ### Deep modules (small interface, deep implementation) - IF: an interface feels too wide, too many methods, or wraps trivial logic - THEN: Read `./references/deep-modules.md` - EXAMPLES: - "is this module too shallow?" - "should I split or combine these classes?" - "this wrapper does almost nothing — keep it?" ### Refactor candidates after GREEN - IF: all tests pass and you're entering the refactor step - THEN: Read `./references/refactoring.md` - EXAMPLES: - "what should I refactor now that tests pass?" - "I see duplication — extract or leave?" - "the new code makes the old code look bad — what do I do?" ## Works well with Optional collaborators — `tdd` runs standalone and these degrade gracefully if absent. - **`grill-with-docs`** (or `grill-me`) — align on scope, interface, and behaviors before the first test; `grill-with-docs` also records the ADRs `tdd` should respect. - **`living-plan`** — its `build` workflow delegates the test-first implementation of each task to `tdd`, handing over the plan's behaviors as the approved design. `tdd` stays fully usable without it. - **`diagnose`** — after a diagnosis pins a bug, lock the fix with a `tdd` regression test. - **`setup-toolbox-context`** — provides the `CONTEXT.md` vocabulary `tdd` uses for test and interface names.
Auf GitHub ansehen