Test-Driven Development

patterns ~2104 tokens updated 2026-08-04

Strict red-green-refactor TDD discipline. No production code without a failing test first. Enforces test-first methodology for all new features and bug fixes.

Tags

  • testing
  • tdd
  • red-green-refactor
  • methodology

README

test-driven-development

Strict red-green-refactor TDD discipline for all new features and bug fixes.

What It Does

Installs a rules file that enforces test-first development:

  • RED - Write a failing test that demonstrates desired behavior
  • GREEN - Write the simplest code to make it pass
  • REFACTOR - Clean up while keeping tests green

Covers new features (test each behavior incrementally), bug fixes (reproduce first, then fix), test quality standards, and when TDD may be skipped (with user approval).

Manual Installation

# Global (all projects)
mkdir -p ~/.claude/rules
cp rules/test-driven-development.md ~/.claude/rules/test-driven-development.md
cp rules/testing-anti-patterns.md ~/.claude/rules/testing-anti-patterns.md

# Project-level
mkdir -p .claude/rules
cp rules/test-driven-development.md .claude/rules/test-driven-development.md
cp rules/testing-anti-patterns.md .claude/rules/testing-anti-patterns.md

Files

File Description
rules/test-driven-development.md TDD methodology with cycle rules, quality standards, and skip criteria
rules/testing-anti-patterns.md Five testing mistakes agents default to under pressure, each with a Gate Function

Will install

Path Action Target Type
rules/test-driven-development.md rules/test-driven-development.md rule
rules/testing-anti-patterns.md rules/testing-anti-patterns.md rule

Dependencies

No dependencies.

Required by

No other module depends on this one.

Included in presets

Install this module

Agent prompt

Recommended for agent users -- hands the whole install off to your assistant.

Fetch https://cd23a9be.ccgm-site.pages.dev/modules/test-driven-development.md and install this module into my Claude Code setup.

Native plugin marketplace

One command via the native plugin marketplace -- additive, does not merge settings.json.

claude plugin install test-driven-development@ccgm

The marketplace path is additive, not a replacement: it installs commands, agents, and skills as native plugin components, but it does not perform the bash installer's deep settings.json merge, and it does not write the always-loaded global CLAUDE.md context. Rules are only injected via an opt-in SessionStart hook rather than being auto-loaded. Use the bash installer when those pieces matter to you.

Manual, per file

Full control -- copy exactly the files you want from the sections below.

Files

Files

rule (2)

rules/test-driven-development.md

# Test-Driven Development

**Iron Law:** NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST.

Violating the letter of this rule is violating the spirit of this rule. If you did not watch the test fail, you do not know if it tests the right thing.

**Announce at start:** "I'm using the TDD discipline. Writing the failing test first."

## The Red-Green-Refactor Cycle

### 1. RED - Write a Failing Test

- Write the smallest test that demonstrates the desired behavior
- Run it and confirm it fails
- Confirm it fails for the RIGHT reason (not a syntax error or import issue)

### 2. GREEN - Make It Pass

- Write the simplest code that makes the test pass
- Do not add extra logic, optimization, or future-proofing
- The goal is a passing test, not elegant code

### 3. REFACTOR - Clean Up

- Improve the code while keeping all tests green
- Remove duplication, improve naming, extract functions
- Run tests after each refactoring step

### 4. Repeat

One behavior at a time. Do not batch multiple behaviors into a single cycle.

## Rules

### For New Features

1. Write a test for the first behavior
2. Make it pass
3. Write a test for the next behavior
4. Make it pass
5. Continue until the feature is complete

### For Bug Fixes

1. Write a test that reproduces the bug (it should fail)
2. Confirm it fails for the right reason
3. Fix the bug
4. Confirm the test passes
5. Confirm no other tests broke

### Test Quality

- **One behavior per test** - each test should verify one thing
- **Clear naming** - test name should describe the expected behavior, not the implementation
- **Use real code** - prefer real dependencies over mocks when practical
- **Test behavior, not implementation** - assert on outputs and side effects, not internal state

## When TDD Applies

- New features and functionality
- Bug fixes (reproduce first, then fix)
- Refactoring (tests exist before you change code)
- Complex business logic and utilities

## When to Ask Before Skipping

TDD may not be practical for:
- Exploratory prototypes the user plans to throw away
- Pure UI layout changes with no logic
- Configuration-only changes

If you think TDD does not apply to the current task, say so and get confirmation before writing code without tests.

## Rationalizations That Mean You Are About to Skip TDD

| You are about to say... | The reality is... |
|-------------------------|-------------------|
| "It's too simple to test" | Simple code has simple tests. Write them. |
| "I'll add tests after" | Tests written after the fact prove nothing about correctness. A test you did not watch fail may be passing for the wrong reason. |
| "I already tested it manually" | Manual testing does not prevent regressions. Tomorrow's refactor needs today's automated test. |
| "It's just a refactor" | Refactors without tests are hoping nothing breaks. If tests do not yet exist, they are a prerequisite of the refactor. |
| "This is a one-off script" | One-off code written without tests is code written without understanding. |
| "I'll mock the whole thing" | Heavy mocking tests the mock, not the code. |
| "The test doesn't really matter here" | If the test does not matter, the behavior does not matter. Delete the code instead. |
| "Tests are slow, I'll skip them this time" | "This time" is how every untested codebase was born. |

## Red Flags

Stop and write the test if you catch yourself:

- "One more implementation first, then tests"
- "Being pragmatic, not dogmatic"
- "I'll add coverage later in a follow-up PR"
- Reaching for production code before any test file exists
- Writing or modifying tests AFTER the feature code is already written
- Telling yourself the task is "too small" to bother
- Accepting a passing test you did not watch fail first

rules/testing-anti-patterns.md

# Testing Anti-Patterns

Five testing mistakes agents default to under pressure. Each has a **Gate Function** - a question to ask before writing the test. If the answer is wrong, stop and redesign the test.

This is a companion to the main TDD rule. The red-green-refactor cycle keeps you honest about *when* tests exist. These anti-patterns keep you honest about *what* the tests actually prove.

## 1. Testing Mock Behavior Instead of Real Behavior

The test asserts that a mock was called with certain arguments, not that the real system produced the correct result. When the mock's contract drifts from reality, the test keeps passing while production breaks.

**Gate Function:** "If I deleted the production code under test and replaced it with a stub that just calls the mock, would this test still pass?"

If yes, the test is asserting on the mock, not the behavior. Rewrite it to assert on outputs or observable side effects.

- Prefer integration-style tests that exercise the real collaborators when practical
- When mocking is necessary, assert on the *effect* of the system's behavior, not on the mock's call log
- A passing test that doesn't change when you break the production code is worse than no test

## 2. Test-Only Methods on Production Classes

A method like `_resetForTest()`, `setPrivateField()`, or an otherwise-unjustified public getter exists solely so the test can reach into internals. The production API is now shaped by the test harness.

**Gate Function:** "Would this method exist if I weren't testing?"

If no, the method does not belong on the production class. Options:
- Test the class through its real public API
- Extract the state you want to inspect into a collaborator with its own tested behavior
- Use a test double that exposes internals, not the production class itself

Test-only methods leak test concerns into production, invite misuse, and usually mean the test is coupled to implementation rather than behavior.

## 3. Mocking Without Understanding the Dependency

The agent mocks a library or service without reading its actual interface, then writes assertions that encode incorrect assumptions. The tests pass against the imagined API; production fails against the real one.

**Gate Function:** "Have I read the real dependency's interface, or am I guessing at it?"

Before mocking any dependency:
- Open the real source or docs. Note the actual return types, error shapes, and side effects
- Verify the mock matches - including edge cases (null, empty, failure modes)
- If the dependency is fast and deterministic, prefer using it directly over mocking

Never mock an API you haven't read. The mock is a model of your assumptions, and untested assumptions are the bug.

## 4. Incomplete Mocks

The mock returns only the two or three fields the test happens to assert on. Real responses contain more fields that production code reads, but the test never exercises those paths. Shipped code crashes on a missing property.

**Gate Function:** "If I ran this mock against the real consumer in production, would it satisfy every access the consumer makes?"

- Base mocks on real captured responses when possible (sample from a fixture, not memory)
- When hand-writing a mock, include all fields the production code touches, not only the ones the current test checks
- Prefer typed mocks (schema-validated) that fail loudly when incomplete

An incomplete mock creates a false signal: the test passes because the code never meets the rest of the response shape.

## 5. Tests as Afterthought

Tests are written after the feature "looks right" manually. They are shaped to match the code as written, not to express the behavior the code should have. A test written to match existing code proves only that the code matches itself.

**Gate Function:** "Did I watch this test fail before I wrote the code that makes it pass?"

If no, the test is not a test - it is a snapshot of current behavior, correct or not.

- Always RED first. If you skipped the failing run, delete the test and write it again
- A test that passed on the first run without a confirmed RED state is suspect; re-verify it actually constrains behavior by breaking the code and watching it fail
- Tests written after the fact miss the entire class of bugs the implementation *quietly* has

## Cross-Reference

- The main TDD rule (`test-driven-development.md`) covers when and how tests get written
- The code-quality rule covers broader testing expectations (coverage areas, error handling)
- Anti-pattern #5 (Tests as Afterthought) is the one the TDD cycle structurally prevents - if you are doing red-green-refactor honestly, you cannot fall into it