
tdd
by All-The-Vibes
A comprehensive collection of reusable Agent Skills for Claude Code, GitHub Copilot, Cursor, and other AI coding assistants
SKILL.md
name: tdd description: Test-Driven Development methodology for writing tests before code. Use when developing new features, fixing bugs with test cases, or ensuring high code quality through test-first approach.
Test-Driven Development (TDD) Skill
Core Principle
Write the test first, then make it pass, then refactor.
TDD is a discipline where you:
- Write a failing test
- Write minimal code to make it pass
- Refactor while keeping tests green
This creates well-tested, well-designed code by default.
The TDD Cycle (Red-Green-Refactor)
┌─────────────────────────────────────────────────────────┐
│ TDD CYCLE │
└─────────────────────────────────────────────────────────┘
┌───────────────┐
│ 1. RED │ Write a failing test
│ ❌ Test │ (Test what you want to build)
└───────┬───────┘
│
▼
┌───────────────┐
│ 2. GREEN │ Write minimal code to pass
│ ✅ Test │ (Make it work)
└───────┬───────┘
│
▼
┌───────────────┐
│ 3. REFACTOR │ Improve code quality
│ 🔄 Clean │ (Make it right)
└───────┬───────┘
│
└─────────► Repeat for next behavior
Step 1: RED — Write a Failing Test
What to Test First
Start with the simplest, most basic behavior:
❌ Don't start with: Edge cases, error handling, complex scenarios ✅ Do start with: The happy path, core functionality, simplest use case
Example: Building a Calculator
# test_calculator.py
def test_add_two_positive_numbers():
"""Test the simplest addition case"""
calc = Calculator()
result = calc.add(2, 3)
assert result == 5
Run the Test (Watch it Fail)
pytest test_calculator.py
# Output:
# NameError: name 'Calculator' is not defined
# ✅ GOOD! This is expected (RED phase)
Why this is important: Watching the test fail proves:
- The test actually runs
- The test can detect problems
- You're not testing code that already exists
Step 2: GREEN — Write Minimal Code
Goal: Make the Test Pass (Nothing More)
Write the simplest possible code to make the test pass:
# calculator.py
class Calculator:
def add(self, a, b):
return a + b
Run the Test Again
pytest test_calculator.py
# Output:
# test_calculator.py::test_add_two_positive_numbers PASSED
# ✅ GREEN! Test passes
Resist the urge to:
- Add features that aren't tested
- Handle edge cases you haven't tested for
- Optimize prematurely
- Write "clever" code
At this stage: Working code > Perfect code
Step 3: REFACTOR — Improve the Code
Now Make It Better
With tests passing, you can safely improve code:
# No refactoring needed yet (code is already simple)
# Wait until you have duplication or complexity
Rules for Refactoring
- Tests must stay GREEN
- No behavior changes
- Improve structure, readability, performance
- Commit after successful refactoring
Expanding Functionality
Add More Tests, One at a Time
# test_calculator.py
def test_add_two_positive_numbers():
calc = Calculator()
assert calc.add(2, 3) == 5
def test_add_negative_numbers(): # ← New test
calc = Calculator()
assert calc.add(-1, -1) == -2
def test_add_zero(): # ← New test
calc = Calculator()
assert calc.add(5, 0) == 5
Pattern:
- Write one new test (RED)
- Make it pass (GREEN)
- Refactor if needed
- Repeat
TDD for Bug Fixes
When You Find a Bug
Traditional approach:
- Fix the bug
- Hope it doesn't come back
TDD approach:
- Write a test that demonstrates the bug (RED)
- Fix the code to make test pass (GREEN)
- Refactor if needed
- Bug can't return (test prevents regression)
Example: Bug Fix with TDD
# Bug report: Calculator.divide() crashes when dividing by zero
def test_divide_by_zero_raises_error(): # ← RED (test the bug)
calc = Calculator()
with pytest.raises(ZeroDivisionError):
calc.divide(10, 0)
# Now fix the code to handle this case
# GREEN: Test passes after fix
# REFACTOR: Clean up if needed
Test Organization Patterns
Arrange-Act-Assert (AAA)
Structure tests in three phases:
def test_user_registration():
# ARRANGE — Set up test data
email = "user@example.com"
password = "secure123"
user_service = UserService()
# ACT — Execute the behavior
user = user_service.register(email, password)
# ASSERT — Verify the outcome
assert user.email == email
assert user.password != password # Should be hashed
assert user.id is not None
Given-When-Then (BDD Style)
Alternative pattern (same concept):
def test_shopping_cart_calculates_total():
# GIVEN a cart with items
cart = ShoppingCart()
cart.add_item(Item("Widget", price=10.00))
cart.add_item(Item("Gadget", price=15.00))
# WHEN calculating the total
total = cart.calculate_total()
# THEN the total should be correct
assert total == 25.00
What Makes a Good Test
Characteristics of Good Tests
✅ Fast — Run in milliseconds ✅ Independent — No dependencies on other tests ✅ Repeatable — Same result every time ✅ Self-validating — Clear pass/fail (no manual verification) ✅ Timely — Written before the code (TDD)
Test Naming Conventions
Good test names explain:
- What is being tested
- Under what conditions
- What the expected result is
# ✅ GOOD
def test_add_returns_sum_of_two_positive_numbers()
def test_divide_raises_error_when_divisor_is_zero()
def test_user_registration_sends_confirmation_email()
# ❌ BAD
def test_add()
def test_divide()
def test_registration()
TDD Anti-Patterns to Avoid
1. Writing Tests After Code
❌ Don't:
# Write all the code first
class Calculator:
def add(self, a, b): return a + b
def subtract(self, a, b): return a - b
def multiply(self, a, b): return a * b
# ... then write tests
✅ Do:
# Write test first
def test_add(): ...
# Then write code to pass
class Calculator:
def add(self, a, b): return a + b
# Repeat for next function
2. Testing Implementation Details
❌ Don't test HOW:
def test_sort_uses_quicksort_algorithm():
# Testing internal implementation
sorter = Sorter()
assert sorter.algorithm == 'quicksort'
✅ Do test WHAT:
def test_sort_returns_items_in_ascending_order():
# Testing behavior
sorter = Sorter()
result = sorter.sort([3, 1, 2])
assert result == [1, 2, 3]
3. Over-Mocking
❌ Don't mock everything:
def test_process_order():
mock_db = Mock()
mock_email = Mock()
mock_payment = Mock()
mock_inventory = Mock()
# Test becomes testing mocks, not real behavior
✅ Do mock external dependencies only:
def test_process_order():
mock_payment_gateway = Mock() # External service
# Use real objects for your own code
order_processor = OrderProcessor(mock_payment_gateway)
4. One Giant Test
❌ Don't test everything in one test:
def test_user_system():
# Test registration
# Test login
# Test logout
# Test password reset
# 200 lines of assertions
✅ Do write focused tests:
def test_user_registration_creates_account(): ...
def test_user_login_with_valid_credentials(): ...
def test_user_logout_clears_session(): ...
def test_password_reset_sends_email(): ...
TDD Workflow Example
Building a User Authentication System
Iteration 1: Basic registration
# RED
def test_register_user_with_valid_email():
auth = AuthService()
user = auth.register("user@example.com", "password123")
assert user is not None
# GREEN
class AuthService:
def register(self, email, password):
return User(email=email)
# REFACTOR
# (Code is simple, no refactoring needed yet)
Iteration 2: Password hashing
# RED
def test_register_user_hashes_password():
auth = AuthService()
user = auth.register("user@example.com", "password123")
assert user.password_hash != "password123"
assert len(user.password_hash) > 20 # Hashed value
# GREEN
class AuthService:
def register(self, email, password):
password_hash = bcrypt.hash(password)
return User(email=email, password_hash=password_hash)
# REFACTOR
# Extract password hashing to separate class
class PasswordHasher:
@staticmethod
def hash(password):
return bcrypt.hash(password)
Iteration 3: Email validation
# RED
def test_register_user_with_invalid_email_raises_error():
auth = AuthService()
with pytest.raises(ValueError):
auth.register("not-an-email", "password123")
# GREEN
class AuthService:
def register(self, email, password):
if '@' not in email: # Simple validation
raise ValueError("Invalid email")
password_hash = PasswordHasher.hash(password)
return User(email=email, password_hash=password_hash)
# REFACTOR
# Extract email validation
class EmailValidator:
@staticmethod
def validate(email):
if '@' not in email or '.' not in email:
raise ValueError("Invalid email format")
TDD Benefits
Design Benefits
- Better API design — Writing tests first forces you to think about usage
- Modular code — Testable code is naturally decoupled
- YAGNI — You only build what's tested (what's needed)
Quality Benefits
- High test coverage — Code is tested by default
- Regression prevention — Tests catch breaking changes
- Living documentation — Tests show how code should be used
Workflow Benefits
- Confidence to refactor — Tests prove behavior unchanged
- Faster debugging — Test pinpoints exact failure
- Clear progress — Each passing test is visible progress
Integration with Other Skills
With Refactoring Skill
- TDD makes refactoring safe (tests prove behavior unchanged)
- Refactor step is built into TDD cycle
- Always refactor with GREEN tests
With Code Review Skill
- TDD code comes with tests (review checklist item)
- Tests document intended behavior
- Easier to review (test shows expected behavior)
With Git Hygiene
- Commit after each RED-GREEN-REFACTOR cycle
- Atomic commits for each new behavior
- Commit message: "test: add validation for X"
Quick Reference
TDD Cycle
- RED — Write failing test
- GREEN — Write minimal code to pass
- REFACTOR — Improve code quality
- Repeat
Test Structure (AAA)
def test_behavior():
# ARRANGE — Set up
# ACT — Execute
# ASSERT — Verify
When to TDD
✅ New features ✅ Bug fixes (test the bug first) ✅ Refactoring (tests enable safe refactoring) ✅ Learning new APIs (tests are documentation)
When NOT to TDD
❌ Prototyping/experimenting (TDD after design is clear) ❌ UI layout (use visual testing instead) ❌ Performance tuning (benchmark, don't TDD)
Remember: TDD is a discipline. It feels slow at first, but leads to faster development over time. Red-Green-Refactor. Test first, code second, refactor third. Small steps, frequent commits, always keep tests passing.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon