Skip to main content
Featured TDD Testing Workflow Automation

Claude Code TDD: AI-Assisted Test-Driven Dev Guide

Learn how to implement TDD with Claude Code. Includes complete Red-Green-Refactor process, Hooks automation configuration, and CLAUDE.md setup examples.

January 19, 2026 10 min read By Claude World

TDD (Test-Driven Development) is one of Anthropic’s officially recommended Claude Code workflows. This article teaches you how to make Claude automatically follow the Red-Green-Refactor cycle to write higher quality code.


Why TDD + Claude Code?

Claude Code excels at tasks with clear targets. Tests are the best targets:

Traditional: Write code → Manual test → Find bugs → Fix → Repeat

TDD: Write test → Test fails (Red) → Write code to pass (Green) → Refactor

Advantages of Claude + TDD:

AdvantageDescription
Clear success criteriaTests pass = Task complete
Auto-iterationClaude can run tests, see results, fix issues
Less back-and-forthNo manual checking “did it work?”
Code qualityNaturally has test coverage

TDD Basics: Red-Green-Refactor

Three Phases

┌─────────────────────────────────────────────────────────┐
│                                                         │
│    🔴 RED          🟢 GREEN         🔄 REFACTOR        │
│                                                         │
│    Write failing   Write minimal    Improve code       │
│    test            code to pass     keep tests passing │
│                                                         │
│         │              │               │               │
│         ▼              ▼               ▼               │
│    Test must fail  Test must pass   Tests still pass  │
│                                                         │
└─────────────────────────────────────────────────────────┘

Practical Example

Step 1: Red

You: Write a test that verifies add(2, 3) returns 5

Claude:
// add.test.js
test('add(2, 3) should return 5', () => {
  expect(add(2, 3)).toBe(5);
});

// Run tests
npm test
// ❌ FAIL - add is not defined

Step 2: Green

You: Make the test pass

Claude:
// add.js
function add(a, b) {
  return a + b;
}

// Run tests
npm test
// ✅ PASS

Step 3: Refactor

You: Refactor the code, add type checking

Claude:
// add.ts
function add(a: number, b: number): number {
  return a + b;
}

// Run tests
npm test
// ✅ PASS (tests still pass)

CLAUDE.md Configuration

Basic TDD Rules

Add to CLAUDE.md in project root:

# TDD Development Rules

## Core Principles
1. **Tests first**: Any new feature must have failing tests first
2. **Minimal implementation**: Only write code just enough to pass tests
3. **Continuous refactoring**: Consider refactoring after each green light

## Development Flow
1. Receive requirement → Write tests first
2. Confirm test fails (Red)
3. Write minimal code to pass tests (Green)
4. Refactor (keep Green)
5. Repeat

## Forbidden
- ❌ Don't write feature code without tests
- ❌ Don't delete or skip existing tests
- ❌ Don't write "tests later" code

Hooks Automation Configuration

Auto-Run Tests

Auto-run tests after every code modification:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --passWithNoTests --watchAll=false 2>/dev/null",
            "onFailure": "warn"
          }
        ]
      }
    ]
  }
}

Force TDD: Tests Must Pass to Complete

{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --passWithNoTests",
            "onFailure": "block"
          }
        ]
      }
    ]
  }
}

Complete TDD Hook Configuration

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if writing feature code. If yes, confirm corresponding test file exists. If test doesn't exist, remind to write tests first. Return 'approve' or reminder message."
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --passWithNoTests --watchAll=false",
            "onFailure": "warn"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check: 1) Was feature code added or modified? 2) If yes, do corresponding tests exist and pass? If tests don't exist or fail, return 'block' with explanation. Otherwise return 'approve'."
          },
          {
            "type": "command",
            "command": "npm test",
            "onFailure": "block"
          }
        ]
      }
    ]
  }
}

Practical Example: Todo App

Let’s implement a simple Todo feature using TDD.

Step 1: Define Requirements

Requirements: Implement TodoList class
- addTodo(text): Add todo item
- getTodos(): Get all todos
- completeTodo(id): Mark as complete
- getCompletedCount(): Get completed count

Step 2: First Test (Red)

You: Implement TodoList using TDD. Write the first test: add todo item.

Claude generates:

// todoList.test.js
const { TodoList } = require('./todoList');

describe('TodoList', () => {
  describe('addTodo', () => {
    test('should add a todo item', () => {
      // Arrange
      const todoList = new TodoList();

      // Act
      todoList.addTodo('Buy milk');

      // Assert
      const todos = todoList.getTodos();
      expect(todos).toHaveLength(1);
      expect(todos[0].text).toBe('Buy milk');
    });
  });
});

Run tests:

npm test
# ❌ FAIL - Cannot find module './todoList'

Step 3: Minimal Implementation (Green)

You: Make the test pass, write minimal code.

Claude generates:

// todoList.js
class TodoList {
  constructor() {
    this.todos = [];
  }

  addTodo(text) {
    this.todos.push({ text });
  }

  getTodos() {
    return this.todos;
  }
}

module.exports = { TodoList };

Run tests:

npm test
# ✅ PASS

Step 4: Next Test

You: Continue TDD, add test for completeTodo feature.
// todoList.test.js (add)
describe('completeTodo', () => {
  test('should mark a todo as completed', () => {
    // Arrange
    const todoList = new TodoList();
    todoList.addTodo('Buy milk');
    const todoId = todoList.getTodos()[0].id;

    // Act
    todoList.completeTodo(todoId);

    // Assert
    const todo = todoList.getTodos()[0];
    expect(todo.completed).toBe(true);
  });
});
npm test
# ❌ FAIL - todo.id is undefined

Step 5: Expand Implementation

You: Make the test pass.
// todoList.js (updated)
class TodoList {
  constructor() {
    this.todos = [];
    this.nextId = 1;
  }

  addTodo(text) {
    this.todos.push({
      id: this.nextId++,
      text,
      completed: false
    });
  }

  getTodos() {
    return this.todos;
  }

  completeTodo(id) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
      todo.completed = true;
    }
  }
}

module.exports = { TodoList };
npm test
# ✅ PASS (2 tests)

TDD FAQ

Q: When is TDD not suitable?

A:

  • Exploratory prototypes (unsure what to build)
  • UI style adjustments
  • Configuration file changes

In these cases, write code first, add tests later.

Q: How detailed should tests be?

A: Follow the testing pyramid:

      /\
     /  \     E2E (few)
    /----\
   /      \   Integration (medium)
  /--------\
 /          \ Unit tests (many)

Q: Claude skips tests and writes code directly?

A: Be explicit in the prompt:

You: Implement this feature using TDD.
    Step 1: Write failing tests first
    Step 2: After I confirm tests fail, then write code

Or use Hooks to enforce:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "If writing feature code (not tests), check if test file exists. If not, return 'block' and remind to write tests first."
          }
        ]
      }
    ]
  }
}

Best Practices Summary

1. Prompt Template

Implement [feature description] using TDD:
1. Write failing tests first
2. After confirming tests fail, write minimal code to pass
3. After all tests pass, consider refactoring

2. Checklist

For each new feature:

  • Write tests first
  • Confirm tests fail (Red)
  • Write code to pass tests (Green)
  • Refactor (keep Green)
  • Check coverage
ToolPurpose
CLAUDE.mdDefine TDD rules
HooksAuto-run tests
Stop HookForce tests to pass

Next Steps

After mastering TDD workflow, recommended reading:

  1. Hooks Complete Tutorial - More automation configurations
  2. Custom Agents - Create dedicated testing agents
  3. Director Mode - Advanced development mode

Resources


Last updated: 2026-01-19