| name | tdd |
| description | Test-Driven Development workflow. Use for ALL code changes - features, bug fixes, refactoring. TDD is non-negotiable. |
Test-Driven Development
TDD is the fundamental practice. Every line of production code must be written in response to a failing test.
This skill focuses on the TDD workflow/process.
RED-GREEN-REFACTOR Cycle
RED: Write Failing Test First
- NO production code until you have a failing test
- Test describes desired behavior, not implementation
- Test should fail for the right reason
GREEN: Minimum Code to Pass
- Write ONLY enough code to make the test pass
- Resist adding functionality not demanded by a test
- Commit immediately after green
REFACTOR: Assess Improvements
- Assess AFTER every green (but only refactor if it adds value)
- Commit before refactoring
- All tests must pass after refactoring
TDD Evidence in Commit History
Default Expectation
Commit history should show clear RED โ GREEN โ REFACTOR progression.
Ideal progression:
commit abc123: [MAINTENANCE] Add failing test for user authentication
commit def456: [NEW FEATURE] Implement user authentication to pass test
commit ghi789: [MAINTENANCE] Extract validation logic for clarity
Rare Exceptions
TDD evidence may not be linearly visible in commits in these cases:
1. Multi-Session Work
- Feature spans multiple development sessions
- Work done with TDD in each session
- Commits organized for PR clarity rather than strict TDD phases
- Evidence: Tests exist, all passing, implementation matches test requirements
2. Context Continuation
- Resuming from previous work
- Original RED phase done in previous session/commit
- Current work continues from that point
- Evidence: Reference to RED commit in PR description
3. Refactoring Commits
- Large refactors after GREEN
- Multiple small refactors combined into single commit
- All tests remained green throughout
- Evidence: Commit message notes "refactor only, no behavior change"
Documenting Exceptions in PRs
When exception applies, document in PR description:
## TDD Evidence
RED phase: commit c925187 (added failing tests for shopping cart)
GREEN phase: commits 5e0055b, 9a246d0 (implementation + bug fixes)
REFACTOR: commit 11dbd1a (test isolation improvements)
Test Evidence:
โ
4/4 tests passing (7.7s with 4 workers)
Important: Exception is for EVIDENCE presentation, not TDD practice. TDD process must still be followed - these are cases where commit history doesn't perfectly reflect the process that was actually followed.
Coverage Verification - CRITICAL
NEVER Trust Coverage Claims Without Verification
Always run coverage yourself before approving PRs.
Verification Process
Before approving any PR claiming "100% coverage":
-
Check out the branch
git checkout feature-branch
-
Run coverage verification:
uv run pytest --cov --cov-report=term-missing
-
Verify ALL metrics hit 100%:
- Lines: 100% โ
- Statements: 100% โ
- Branches: 100% โ
- Functions: 100% โ
-
Check that tests are behavior-driven (not testing implementation details)
Watch for anti-patterns that create fake coverage (coverage theater).
Reading Coverage Output
Look for the "All files" line in coverage summary:
Name Stmts Miss Cover Missing
-------------------------------------------------
src/models.py 42 0 100%
src/services.py 38 0 100%
src/utils.py 15 0 100%
-------------------------------------------------
TOTAL 95 0 100%
โ
This is 100% coverage.
Red Flags
Watch for these signs of incomplete coverage:
โ PR claims "100% coverage" but you haven't verified
- Never trust claims without running coverage yourself
โ Coverage summary shows <100%
TOTAL 95 8 92%
- This is NOT 100% coverage
โ "Missing" column shows line numbers
src/services.py 38 5 87% 45-48, 52
- Lines 45-48 and 52 are not covered
โ Coverage gaps without exception documentation
- If coverage <100%, document the reason and get approval
When Coverage Drops, Ask
"What business behavior am I not testing?" โ not "What line am I missing?"
Development Workflow
Adding a New Feature
- Write failing test โ describe expected behavior
- Run test โ confirm it fails (
uv run pytest)
- Implement minimum โ just enough to pass
- Run test โ confirm it passes
- Refactor if valuable โ improve code structure
- Commit โ following project commit convention
Workflow Example
def test_reject_empty_user_names():
result = create_user(id="user-123", name="")
assert result.success is False
def create_user(id: str, name: str) -> CreateUserResult:
if not name:
return CreateUserResult(success=False, error="Name required")
...
Pull Request Requirements
Before submitting PR:
Refactoring Priority
After green, classify any issues:
| Priority | Action | Examples |
|---|
| Critical | Fix now | Mutations, knowledge duplication, >3 levels nesting |
| High | This session | Magic numbers, unclear names, >30 line functions |
| Nice | Later | Minor naming, single-use helpers |
| Skip | Don't change | Already clean code |
For detailed refactoring methodology, load the refactoring skill.
Anti-Patterns to Avoid
- โ Writing production code without failing test
- โ Testing implementation details (spies on internal methods)
- โ 1:1 mapping between test files and implementation files
- โ Using mutable module-level state or fixtures for shared test data
- โ Trusting coverage claims without verification
- โ Mocking the function being tested
- โ Redefining schemas in test files
- โ Factories returning partial/incomplete objects
- โ Speculative code ("just in case" logic without tests)
Summary Checklist
Before marking work complete: