Red-Green-Refactor cycle for test-first development. Write failing test, implement minimal code, refactor safely. Use when developing new features or fixing bugs in test-driven projects.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
tdd-workflow
description
Red-Green-Refactor cycle for test-first development. Write failing test, implement minimal code, refactor safely. Use when developing new features or fixing bugs in test-driven projects.
context
fork
agent
general-purpose
allowed-tools
Read, Grep, Glob, Write, Edit, Bash
TDD Workflow
Disciplined test-first development with the Red-Green-Refactor cycle. Tests shape API design; fearless refactoring becomes possible.
Context
You are guiding the engineer through TDD. Your role is to help them:
Write clear, focused tests that describe desired behavior before implementation
Implement minimal code that passes the test (no over-engineering)
Refactor with confidence, knowing tests will catch mistakes
Keep cycles short (5-15 minutes) to maintain momentum
Use test failures as design feedback
TDD is not just about testing; it's about using tests as a design tool to improve code clarity and maintainability.
Domain Context
Based on Kent Beck, Bob Martin, and J.B. Rainsberger:
Red Phase: Write test describing desired behavior; it fails because feature doesn't exist. This failure is essential—it proves the test actually tests something.
Green Phase: Write minimal code to pass the test. "Minimal" means: just enough logic; no premature optimization; no extra features.
Refactor Phase: Improve code without changing behavior. Extract methods, improve names, reduce duplication. Tests protect against regressions.
Design Feedback: If tests are hard to write, the API is hard to use. If mocking is complex, coupling is too tight. Tests reveal design problems early.
Regression Safety: Previous tests continue passing, so refactoring is fearless. This enables continuous improvement.
Cycle Length: 5-15 minutes per cycle. Longer cycles indicate the test is too complex; break it down.
When to Use This Skill
Starting a new feature where behavior is well-defined
Fixing a bug (write test for the bug first, then implement fix)
Adding to a codebase already using TDD (maintain consistency)
When you want to confidently refactor without fear of regressions
When API design is uncertain (tests force clarity)
Prerequisites
Before starting TDD, confirm:
Clear Requirements: Understand what "done" looks like for this feature
Test Framework: Know how to write tests in your language (unittest, pytest, Jest, xUnit)
Development Environment: Can run tests locally in <5 seconds
Existing Tests: Review existing tests to match style and patterns
Integration Plan: Where will this code plug into the system?
Run all tests. Both pass. The implementation evolved because tests revealed missing behavior.
7. Repeat: Write Next Test
Start again at step 2. Each cycle improves the implementation and test coverage.
Example test sequence for email validator:
Test missing @ → minimal implementation
Test valid email → refactor to handle domain
Test spaces in email → refactor validation
Test multiple @ symbols → refactor parsing
Test empty local part → refactor
Eventually: regex or use a library
Each test adds one behavioral requirement. The implementation grows steadily, staying simple.
8. Watch for Long Cycles
If a cycle takes >15 minutes:
Break test into smaller pieces (test one behavior per test)
Implementation might need a helper function (implement with next test)
You might be over-engineering; step back and check requirements
Output Format
When using this skill, deliver:
Test Code: Failing test demonstrating desired behavior (Red)
Implementation: Minimal code passing the test (Green)
Refactored Code: Improved implementation if duplication emerged (Refactor)
Test Suite Status: All tests passing, no regressions
Next Test: What behavior should the next test verify?
Example output structure:
## Red: Write Test
[test code showing failure]
## Green: Implement
[minimal implementation]
## Verify
- Test passes: ✓
- Suite passes: ✓
- No regressions: ✓
## Refactor (if needed)
[improved code with better names/structure]
## Next Cycle
The next test should verify [specific behavior], because [reason].
Worked Example
Feature: User password strength validator
Requirement: Passwords must be 8+ characters, contain uppercase, lowercase, digit, and special character.
deftest_password_rejects_missing_uppercase():
validator = PasswordValidator()
assert validator.is_strong("password1!") isFalse# no uppercase
Green: Implement
classPasswordValidator:
defis_strong(self, password: str) -> bool:
iflen(password) < 8:
returnFalsereturnany(c.isupper() for c in password)
Verify: Both tests pass.
Cycle 3: Test requires lowercase
Red: Test
deftest_password_rejects_missing_lowercase():
validator = PasswordValidator()
assert validator.is_strong("PASSWORD1!") isFalse# no lowercase
Green: Implement
classPasswordValidator:
defis_strong(self, password: str) -> bool:
iflen(password) < 8:
returnFalseifnotany(c.isupper() for c in password):
returnFalsereturnany(c.islower() for c in password)
Verify: All three tests pass.
Cycle 4: Test requires digit
Red: Test
deftest_password_rejects_missing_digit():
validator = PasswordValidator()
assert validator.is_strong("Password!") isFalse# no digit
Green: Implement
classPasswordValidator:
defis_strong(self, password: str) -> bool:
iflen(password) < 8:
returnFalseifnotany(c.isupper() for c in password):
returnFalseifnotany(c.islower() for c in password):
returnFalsereturnany(c.isdigit() for c in password)
Verify: All four tests pass.
Cycle 5: Test requires special character
Red: Test
deftest_password_rejects_missing_special_char():
validator = PasswordValidator()
assert validator.is_strong("Password1") isFalse# no special char
Green: Implement
classPasswordValidator:
SPECIAL_CHARS = "!@#$%^&*()-_=+[]{}|;:',.<>?/`~"defis_strong(self, password: str) -> bool:
iflen(password) < 8:
returnFalseifnotany(c.isupper() for c in password):
returnFalseifnotany(c.islower() for c in password):
returnFalseifnotany(c.isdigit() for c in password):
returnFalsereturnany(c inself.SPECIAL_CHARS for c in password)
Verify: All five tests pass.
Cycle 6: Refactor
Notice repetition in validation checks. Extract helper:
classPasswordValidator:
SPECIAL_CHARS = "!@#$%^&*()-_=+[]{}|;:',.<>?/`~"defis_strong(self, password: str) -> bool:
return (
self._has_min_length(password, 8)
andself._has_uppercase(password)
andself._has_lowercase(password)
andself._has_digit(password)
andself._has_special_char(password)
)
def_has_min_length(self, password: str, length: int) -> bool:
returnlen(password) >= length
def_has_uppercase(self, password: str) -> bool:
returnany(c.isupper() for c in password)
def_has_lowercase(self, password: str) -> bool:
returnany(c.islower() for c in password)
def_has_digit(self, password: str) -> bool:
returnany(c.isdigit() for c in password)
def_has_special_char(self, password: str) -> bool:
returnany(c inself.SPECIAL_CHARS for c in password)
Verify: All tests still pass. Refactoring complete.
Green: Already implemented; test passes immediately.
Decision Framework
When writing tests, use these decisions:
If unclear how feature should behave: Write a test capturing your understanding. Discuss with product owner.
If implementation is taking >15 min: Break cycle into smaller test. Implementation is too complex for one test.
If test is hard to write: Consider design. Is the API easy to use? Does it have too many dependencies?
If test requires complex mocking: Implementation has tight coupling. Consider refactoring.
If test passes without new implementation: Test is redundant; skip it or combine with another test.
If adding feature breaks existing tests: Don't change tests; fix implementation to satisfy both old and new requirements.
Anti-Patterns (Expanded)
1. Skipping Red Phase
Mistake: Write code, then write tests afterward.
Why LLMs make this: Implementing feels like progress; tests feel like overhead. Code-first pressure is high.
Guard: Before writing any implementation, write a test that currently fails. Run it; confirm failure message is clear.
Example:
Bad: Write EmailValidator.is_valid() implementation, then write test
Good: Write test that fails, then implement is_valid()
2. Writing Tests After Code
Mistake: Implement feature; then write tests to verify it works.
Why LLMs make this: Tests are supposed to document behavior; code already documents behavior.
Guard: Tests written first reveal design problems that post-hoc tests miss. Make it a workflow rule.
Example:
Bad: Implement UserService.create_user(), then write test
Good: Write test of UserService.create_user() first; implement after
3. Over-Engineering in Green Phase
Mistake: Implement "production-quality" code on first pass (optimization, generalization, error handling).
Why LLMs make this: Training emphasizes complete, robust implementations.
Guard: If implementation doesn't feel deliberately naive, you're over-engineering. Write simplest code that passes test; refactor later.
Example:
Bad: Implement regex email validation on first test; refactor later
Good: Implement "@" in email on first test; evolve with each test
4. Not Running Tests Frequently
Mistake: Write multiple tests without running; run them all at once.
Why LLMs make this: Batching feels efficient.
Guard: Run tests after each Red-Green-Refactor cycle. Rapid feedback (minutes, not hours) reveals problems immediately.
Example:
Bad: Write 5 tests, implement 5 features, run tests once
Good: Red-Green-Refactor each test individually; run after each cycle
5. Refactoring Without Running Tests
Mistake: Refactor code, then run tests later; hope nothing broke.
Why LLMs make this: Large refactors feel productive.
Guard: Before refactoring, tests must pass. After each small refactoring step (rename, extract, move), run tests. If tests fail, revert and try smaller step.
Example:
Bad: Refactor entire validation class; run tests once at end
Good: Rename one variable, run tests; extract one method, run tests; repeat
6. Unclear Test Names
Mistake: Write tests with names like test_email() or test_password_1().
Why LLMs make this: Generating descriptive names takes extra effort.
Guard: Test name should describe the condition and expected outcome. Read the test name aloud; does it explain what's being tested?