| name | tdd-workflow |
| description | Python-specific TDD wrapper. Use INSTEAD OF superpowers:test-driven-development when the project uses uv + pytest. Adds: feedback loading from autonomous-sdlc, uv run pytest commands, test directory organization (unit/integration/e2e). Delegates core TDD discipline to superpowers:test-driven-development. Trigger: "TDD", "test first", "red green refactor", "write a failing test" in any Python/pytest project.
|
| version | 1.0.0 |
| effort | high |
| allowed-tools | ["Bash","Read","Write","Edit"] |
Test-Driven Development Workflow
Goal
Enforce the discipline of writing tests before implementation code. Every feature starts with a failing test (RED), passes with minimal code (GREEN), then improves through refactoring while green. Never skip the test-first step.
Dependencies
Tools
- pytest — Test runner. Invoked via
uv run pytest.
- Bash — Runs test commands to confirm RED/GREEN status.
Connectors
- Project test infrastructure — Existing
tests/ directory with pytest configuration.
Context
The Red-Green-Refactor Cycle
RED: Write failing test
↓
GREEN: Write minimal code to pass
↓
REFACTOR: Improve code while keeping tests green
↓
(repeat)
TDD Rules
- Never write production code without a failing test
- Write only enough test to fail (compilation failures count)
- Write only enough code to pass the failing test
- Refactor only when tests are green
Test Organization
tests/
├── unit/ # Fast, isolated tests
├── integration/ # Tests with real dependencies
└── e2e/ # Full system tests
Coverage Guidance
Focus on meaningful coverage, not 100%:
- Critical business logic: 90%+
- Edge cases and error paths
- Integration points
Don't obsess over: simple getters/setters, framework boilerplate, generated code.
Process
Step 0: Load Stored Feedback
python ${CLAUDE_PLUGIN_ROOT}/scripts/feedback_manager.py autonomous-sdlc show-feedback
Apply relevant feedback: tdd_workflow, test_generation, general.
Step 1: RED — Write a Failing Test
def test_create_user_returns_user_with_id():
"""Test that creating a user returns a user with an assigned ID."""
service = UserService()
user = service.create_user(name="Alice", email="alice@example.com")
assert user.id is not None
assert user.name == "Alice"
assert user.email == "alice@example.com"
Run to confirm failure:
uv run pytest tests/test_user_service.py::test_create_user_returns_user_with_id -x
Step 2: GREEN — Minimal Implementation
Write just enough code to make the test pass:
from dataclasses import dataclass
import uuid
@dataclass
class User:
id: str
name: str
email: str
class UserService:
def create_user(self, name: str, email: str) -> User:
return User(id=str(uuid.uuid4()), name=name, email=email)
Run to confirm pass:
uv run pytest tests/test_user_service.py::test_create_user_returns_user_with_id -x
Step 3: REFACTOR — Improve Structure While Green
Refactoring means improving code structure without changing behavior. Do not add new features here.
from dataclasses import dataclass, field
import uuid
@dataclass
class User:
name: str
email: str
id: str = field(default_factory=lambda: str(uuid.uuid4()))
class UserService:
def create_user(self, name: str, email: str) -> User:
return User(name=name, email=email)
uv run pytest tests/test_user_service.py -x
Step 4: Next RED Cycle — Add Validation
New behavior requires a new failing test first:
def test_create_user_validates_empty_name():
service = UserService()
with pytest.raises(ValueError, match="Name cannot be empty"):
service.create_user(name="", email="test@example.com")
uv run pytest tests/test_user_service.py -x
class UserService:
def create_user(self, name: str, email: str) -> User:
if not name.strip():
raise ValueError("Name cannot be empty")
return User(name=name, email=email)
Then repeat for email validation, normalization, etc. — always RED first.
Test-First Checklist
Before implementing any feature:
Output
Working tests and implementation code produced through the red-green-refactor cycle. The test suite serves as living documentation of the system's behavior.