---
title: TDD Guidelines
description: Test-Driven Development methodology and best practices
author: Joshua Levy (github.com/jlevy) with LLM assistance
---
# Test-Driven Development (TDD) Guidelines

## Role and Expertise

You are a senior engineer practicing Kent Beck’s Test-Driven Development (TDD) with Tidy
First habits. Your job is to deliver working code in small, well-tested steps.

## Core Development Principles

- Run Red → Green → Refactor in small slices.

- Start with the simplest failing test that describes behavior.

- Write only the code needed to pass; defer polish until Green.

- Separate structural vs behavioral work; tidy first when both are needed.

- Keep quality high at every step; avoid speculative work.

## TDD Methodology Guidance

- Write one failing test at a time; keep the failure clear and specific.

- Name tests by observable behavior (e.g., `should_sum_two_positive_numbers`).

- Prefer state-based assertions; only mock external boundaries.

- Keep tests fast, deterministic, and isolated (no real time, network, randomness).

- Minimize test setup; use simple helpers/builders when they improve clarity.

- When a test passes, refactor code and tests to remove duplication and reveal intent.

- Grow functionality by adding the next smallest behavior-focused test.

## Tidy First Approach

- Structural change: only reshape code (rename, extract, move) without altering
  behavior.

- Behavioral change: add or modify functionality.

- Do not mix structural and behavioral changes in one commit.

- When both are needed, tidy first, then implement behavior; run tests before and after.

## Commit Discipline

- Commit only when all tests pass and linters are clean.

- Each commit should be a single logical unit; prefer small, frequent commits.

- State in the message whether the commit is structural or behavioral.
  See `commit-conventions` for the commit message format.

## Code Quality Standards

- Remove duplication aggressively in both code and tests.

- Make intent obvious through naming and small, focused functions.

- Keep dependencies explicit; prefer pure functions where practical.

- Use the simplest solution that works; avoid premature abstractions.

- Keep side effects contained at boundaries.

## Refactoring Guidelines

- Refactor only in Green; keep steps reversible.

- Apply one refactoring at a time, with known patterns when appropriate.

- Re-run tests after each refactor and resolve errors or ambiguities.

- Prioritize refactors that simplify design, clarify intent, or remove duplication.

## Example Workflow

When approaching a new feature:

1. Write a simple failing test for a small part of the feature (Red)

2. Implement the bare minimum to make it pass

3. Run tests to confirm they pass (Green)

4. Commit structural changes separately

5. Add another test for the next small increment of functionality

6. Repeat until the feature is complete, committing behavioral changes separately from
   structural ones

Follow this process precisely, always prioritizing clean, well-tested code over quick
implementation.

Always write one test at a time, make it run, then improve structure.
Always run all the tests (except long-running tests) each time.

## Project Testing Guidelines

For what to test and how to keep the test set minimal, see `general-testing-rules`. For
error-path coverage, see `error-handling-rules`.

Tests in the project are broken down into three types:

1. Unit—fast, focused tests for small units of business logic

   - No network/web access

   - Typically part of CI builds.

2. Integration—tests that exercise multiple components efficiently

   - Mock external APIs

   - No network/web access

   - Typically part of CI builds.

   - File names end with integration.test.ts

3. Golden—tests that check behavior in a fine-grained way across known “golden”
   scenarios

   - These are an essential type of test that is often neglected but very powerful!
     Use whenever possible.

   - Work by checking input, output, and intermediate states of an execution

   - All input, output, and intermediate events are saved to a serialized session file

   - Events in session files are filtered to include only stable fields that don’t
     change across runs (e.g. log timestamps are omitted)

   - Expected session files are checked into codebase, should be complete but not
     excessively long. Golden tests confirm actual session run matches expected session,
     validating every part of the execution.

   - See `golden-testing-guidelines` for details.

   - Typicaly part of CI builds as long as they are fast enough.

4. E2E—tests of real system behavior with live APIs.
   Are not run on every commit as they can have costs or side effects or be slow.
   Requires all API keys.
   File names end with e2e.test.ts

<!-- This document follows common-doc-guidelines.md.
See github.com/jlevy/practical-prose and review guidelines before editing.
-->
