TDD guidance for writing tests, using test doubles, and ensuring high code coverage.
Install
mkdir -p .claude/skills/tdd-kennedym-ds && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18735" && unzip -o skill.zip -d .claude/skills/tdd-kennedym-ds && rm skill.zipInstalls to .claude/skills/tdd-kennedym-ds
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
TDD patterns for Red-Green-Refactor cycles, unit/integration testing, test doubles, and coverage analysis. Use for writing tests before implementation and validating code changes.Key capabilities
- →Implement new features using TDD
- →Fix bugs with reproducible test cases
- →Refactor existing code with a safety net
- →Establish baseline test coverage
- →Validate edge cases and error handling
- →Apply Red-Green-Refactor cycle
How it works
The process involves writing a failing test (Red), implementing minimal code to make the test pass (Green), and then improving the code quality while ensuring tests still pass (Refactor).
Inputs & outputs
When to use tdd
- →Write unit tests first
- →Create mocks and stubs
- →Improve test coverage
- →Refactor code with test validation
About this skill
Test-Driven Development (TDD)
Provides TDD patterns for writing tests before implementation, following Red-Green-Refactor cycle, and achieving comprehensive test coverage.
Description
This skill teaches implementer and test agents how to apply Test-Driven Development principles: write failing tests first (Red), implement minimal code to pass (Green), then refactor for quality (Refactor). It covers unit testing, integration testing, test doubles (mocks/stubs), and coverage analysis.
When to Use
- Implementing new features or functions
- Fixing bugs with reproducible test cases
- Refactoring existing code with safety net
- Establishing baseline test coverage
- Validating edge cases and error handling
When NOT to Use
- Do not use for documentation-only changes or configuration updates with no testable behavior.
- Do not use for exploratory debugging where the problem is not yet understood — use the researcher or rubber-duck agent first.
Entry Points
Trigger Phrases: "write tests first", "TDD approach", "test coverage", "unit tests", "integration tests", "test this function"
Context Patterns: New feature implementation, bug fixes, refactoring tasks, code review with missing tests
Core Knowledge
Red-Green-Refactor Cycle
1. Red (Write Failing Test)
# test_calculator.py
def test_add_positive_numbers():
calc = Calculator()
result = calc.add(2, 3)
assert result == 5 # FAILS: Calculator not implemented
def test_add_negative_numbers():
calc = Calculator()
result = calc.add(-2, -3)
assert result == -5 # FAILS
2. Green (Minimal Implementation)
# calculator.py
class Calculator:
def add(self, a, b):
return a + b # Simplest code that passes tests
3. Refactor (Improve Code Quality)
# calculator.py
class Calculator:
"""Performs basic arithmetic operations."""
def add(self, a: float, b: float) -> float:
"""Add two numbers and return result."""
return a + b # No refactoring needed (already simple)
Test Pyramid
/\
/ \ E2E Tests (Few, Slow, High Value)
/____\
/ \
/ Integration Tests (Some, Medium Speed)
/________\
/ \
/ Unit Tests (Many, Fast, Focused)
/______________\
Unit Tests (70%): Test individual functions/methods in isolation Integration Tests (20%): Test component interactions (DB, API, services) E2E Tests (10%): Test complete user workflows through UI
Test Doubles
| Type | Purpose | Example |
|---|---|---|
| Stub | Returns fixed data | getUserStub() returns { id: 1, name: 'Test' } |
| Mock | Verifies interactions | Assert sendEmail() called once with correct args |
| Spy | Records invocations | Track how many times logger.info() called |
| Fake | Simplified implementation | In-memory database for tests |
Coverage Metrics
Line Coverage: % of code lines executed during tests Branch Coverage: % of if/else branches exercised Function Coverage: % of functions called Target: ≥80% line coverage, ≥70% branch coverage for new code
TDD Patterns
Pattern 1: Arrange-Act-Assert (AAA)
test('user registration creates account', async () => {
// Arrange: Set up test data and preconditions
const userData = { email: '[email protected]', password: 'secret123' };
// Act: Execute the code under test
const user = await registerUser(userData);
// Assert: Verify expected outcomes
expect(user.id).toBeDefined();
expect(user.email).toBe('[email protected]');
expect(user.password).not.toBe('secret123'); // Should be hashed
});
Pattern 2: Test Edge Cases
def test_divide():
# Happy path
assert divide(10, 2) == 5
# Edge cases
assert divide(0, 5) == 0 # Zero numerator
assert divide(7, 3) == 2.333 # Float result
# Error cases
with pytest.raises(ZeroDivisionError):
divide(10, 0) # Division by zero
Pattern 3: Parameterized Tests
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("WORLD", "WORLD"),
("", ""),
("123", "123"),
])
def test_to_uppercase(input, expected):
assert to_uppercase(input) == expected
Examples
Example: TDD for API Endpoint
Phase 1: Red (Failing Tests)
// tests/api/users.test.js
describe('POST /api/users', () => {
it('creates new user with valid data', async () => {
const res = await request(app)
.post('/api/users')
.send({ name: 'John', email: '[email protected]' });
expect(res.status).toBe(201);
expect(res.body.user.name).toBe('John');
expect(res.body.user.id).toBeDefined();
});
it('returns 400 for missing email', async () => {
const res = await request(app)
.post('/api/users')
.send({ name: 'John' });
expect(res.status).toBe(400);
expect(res.body.error).toContain('email');
});
});
// ⌠Tests FAIL: /api/users endpoint doesn't exist
Phase 2: Green (Minimal Implementation)
// routes/users.js
app.post('/api/users', async (req, res) => {
const { name, email } = req.body;
if (!email) {
return res.status(400).json({ error: 'email is required' });
}
const user = await db.users.create({ name, email });
res.status(201).json({ user });
});
// ✅ Tests PASS
Phase 3: Refactor (Improve Quality)
// routes/users.js
const { body, validationResult } = require('express-validator');
app.post('/api/users',
// Validation middleware
body('email').isEmail().normalizeEmail(),
body('name').trim().isLength({ min: 1, max: 100 }),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { name, email } = req.body;
try {
const user = await db.users.create({ name, email });
res.status(201).json({ user: sanitizeUser(user) });
} catch (err) {
if (err.code === 'UNIQUE_VIOLATION') {
return res.status(409).json({ error: 'Email already exists' });
}
throw err;
}
}
);
// ✅ Tests still PASS, code quality improved
Bundled References
- Test Pyramid — Unit/integration/E2E ratios, coverage targets, decision matrix
- Coverage Config Examples — Jest, pytest, Pester coverage configuration
References
- Testing Frameworks: Jest, Pytest, Mocha, RSpec
- Coverage Tools: nyc, coverage.py, SimpleCov
- Test Agent:
.github/agents/test.agent.md .github/agents/implementer.agent.md— implementation workflow that applies strict TDD disciplineinstructions/workflows/implementer.instructions.md— tests-first execution guardrails for implementer tasks
When not to use it
- →For documentation-only changes or configuration updates with no testable behavior
- →For exploratory debugging where the problem is not yet understood
Limitations
- →Does not apply to documentation-only changes
- →Not for exploratory debugging
How it compares
This skill provides a structured, iterative approach to development that prioritizes testing before implementation, ensuring code quality and preventing regressions.
Compared to similar skills
tdd side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| tdd (this skill) | 0 | 3mo | No flags | Beginner |
| python-testing-patterns | 77 | 2mo | Review | Intermediate |
| pr-review | 6 | 1mo | Review | Intermediate |
| pytest | 8 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
python-testing-patterns
wshobson
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development. Use when writing Python tests, setting up test suites, or implementing testing best practices.
pr-review
pytorch
Review PyTorch pull requests for code quality, test coverage, security, and backward compatibility. Use when reviewing PRs, when asked to review code changes, or when the user mentions "review PR", "code review", or "check this PR".
pytest
prowler-cloud
Pytest testing patterns for Python. Trigger: When writing or refactoring pytest tests (fixtures, mocking, parametrize, markers). For Prowler-specific API/SDK testing conventions, also use prowler-test-api or prowler-test-sdk.
code-change-verification
openai
Run the mandatory verification stack when changes affect runtime code, tests, or build/test behavior in the OpenAI Agents Python repository.
django-verification
affaan-m
Verification loop for Django projects: migrations, linting, tests with coverage, security scans, and deployment readiness checks before release or PR.
python
alinaqi
Python development with ruff, mypy, pytest - TDD and type safety