| name | tdd-master |
| description | This skill should be used when the user asks to "write tests", "add tests", "create test", "implement feature", "fix bug", "TDD", "test-driven", "reproduce bug", "write failing test", "Red-Green-Refactor", or when implementing any new functionality that requires testing. Provides TDD methodology based on Kent Beck and Uncle Bob principles. |
TDD Master Skill
Test-Driven Development methodology for writing reliable, maintainable code.
When to Activate
This skill activates automatically when:
- Implementing new features (write tests FIRST)
- Fixing bugs (reproduce with failing test FIRST)
- Writing or reviewing tests
- Refactoring code (ensure tests exist)
Core Workflow: Red-Green-Refactor
Step 1: Test List
Before coding, create a list of scenarios:
## Test List for [Feature]
- [ ] Happy path: main scenario
- [ ] Edge case: empty input
- [ ] Edge case: boundary values
- [ ] Error case: invalid input
- [ ] Error case: external service failure
Step 2: RED - Write Failing Test
Write test that defines expected behavior:
def test__{what}__{scenario}__{outcome}():
order = Order(items=[Item(price=1500)])
discount = calculate_discount(order)
assert discount == Decimal('150')
CRITICAL: Predict HOW the test will fail before running.
Step 3: GREEN - Minimal Code
Write MINIMUM code to pass:
- Hardcoded values OK
- Simple if-statements OK
- "Fake it till you make it" OK
Step 4: REFACTOR
After test passes:
- Remove duplication
- Improve naming
- Extract helpers
- Keep tests green
Step 5: REPEAT
Next test from list until complete.
Three Laws of TDD (Uncle Bob)
| # | Law |
|---|
| 1 | Cannot write production code without failing test |
| 2 | Cannot write more test than sufficient to fail |
| 3 | Cannot write more production code than sufficient to pass |
FIRST Principles
| Principle | Description |
|---|
| Fast | Tests run quickly |
| Independent | No test dependencies |
| Repeatable | Same result everywhere |
| Self-validating | Clear pass/fail |
| Timely | Written BEFORE code |
Fixture Defaults (P0 Pattern)
| Role | Defaults | Example |
|---|
| FK dependency | Minimal for validity | Campaign(name='Test', status=ACTIVE) |
| Entry point | Maximal for usefulness | create_applicant(with_tilda=True, ...) |
| Edge case | Explicitly marked | create_applicant(with_tilda=False) |
Test Naming Convention
def test__calculate_discount__order_over_1000__returns_10_percent(): ...
def test__calculate_discount__empty_order__returns_zero(): ...
def test__process_payment__timeout__raises_error(): ...
External Service Mocking
Dict-based States (Default - Sync APIs)
def test_get_customer__exists(apibank):
apibank.reg_customer({'code': '123', 'fullName': 'Test'})
result = service.get_customer('123')
assert result.full_name == 'Test'
Queue-based Responses (Async APIs Only)
def test_threshold__fail(fns_admin, create_income_request):
request = create_income_request(protocol.SmzPlatformError(...))
tasks.register_income()
request.refresh_from_db()
assert request.state == IncomeRequestState.ERROR
End-to-End Flow Pattern
One test = One business flow from input to output.
def test__welcome_email__full_flow():
applicant = create_applicant(...)
outbox = create_email_outbox(...)
process_email_outbox()
assert len(mail.outbox) == 1
def test__create_outbox(): ...
def test__process_outbox(): ...
Assertion Helpers
from testing import AnyDict, ReStr, UnorderedList
assert response == AnyDict({
'status': 'success',
'id': ReStr(r'[a-f0-9-]{36}'),
})
assert events == UnorderedList([event1, event2])
Critical Anti-Patterns
The Liar - Always Passes
def test_liar():
assert True
Error Hiding in Tests
if not event.wait(timeout=2):
raise TimeoutError('...')
if not event.wait(timeout=2):
pytest.fail('Test timeout')
Skipping Refactoring
"The most common error is skipping the third step. Refactoring is critical." - Martin Fowler
Framework Detection
CRITICAL: Before writing tests, detect which frameworks the project uses and load the corresponding reference documentation.
Detection Steps
- Analyze project dependencies — check
pyproject.toml, requirements.txt, setup.cfg, Pipfile
- Scan imports in existing test files —
import pytest, import django, import unittest
- Check for config files —
pytest.ini, conftest.py, manage.py, settings.py
Framework Reference Matrix
| Detected | Action | Reference File |
|---|
pytest in dependencies | Read pytest patterns | references/frameworks/pytest.md |
django in dependencies | Read Django patterns | references/frameworks/django.md |
| Both pytest + Django | Read both files | Both files above |
| Neither detected | Use TDD_GUIDE only | references/TDD_GUIDE.md |
Detection Signals
Pytest project:
conftest.py exists
pytest.ini or [tool.pytest] in pyproject.toml
pytest in dependencies
- Test files use
def test_... without class
Django project:
manage.py exists
settings.py or DJANGO_SETTINGS_MODULE env
django in dependencies
pytest-django in dependencies
@pytest.mark.django_db in test files
Loading Order
1. ALWAYS read: references/TDD_GUIDE.md (core methodology)
2. ALWAYS read: references/P0_DEFAULT_CONTEXT.md (context-adaptive defaults)
3. IF pytest detected: references/frameworks/pytest.md
4. IF django detected: references/frameworks/django.md
Reference Documentation
Always Loaded
references/TDD_GUIDE.md - Core TDD methodology (Kent Beck, Uncle Bob, FIRST principles, anti-patterns)
references/P0_DEFAULT_CONTEXT.md - Context-adaptive default values (FK=minimal, entry=maximal, edge=explicit)
Framework-Specific (loaded based on detection)
references/frameworks/pytest.md - Pytest patterns: fixtures, markers, assertion helpers, mocking, conftest organization
references/frameworks/django.md - Django patterns: django_db, factory_boy, background tasks, signals, ESB events, timezone testing
Integration with Other Agents
Other agents can call tdd-master when tests are needed:
- Before implementation — call tdd-master to write failing tests, then implement code to pass them
- During code review — verify new code has tests, flag missing tests as P1 issue
Quick Checklist
Before Writing Test:
When Writing Test:
Before Writing Code:
After Test Passes:
Critical Rules
- Write tests BEFORE implementation
- Predict failure before running
- Write minimal code to pass
- Always refactor after green
- Use
pytest.fail() not raise Exception
- Mock only external services