TDD — テスト駆動開発

一言で

「テストありき」で設計を考える。実装より先にテストを書く。

3ステップサイクル

1
赤 — テストを先に書く

まだ実装がないので、テストは失敗する。入力と期待出力を明確にする。

2
緑 — 最小コードで通す

テストが通る最小のコードを書く。「綺麗さ」より「動くこと」優先。

3
リファクタリング

重複を消す、名前を変える、関数を分割。テストが緑のまま保たれることを確認。

→ 数分単位で高速にサイクルを回す

いつ使うか

対象
ロジック・計算・変換処理があるコード
バグ修正(バグを再現するテストを先に書く)
リファクタリング前(既存動作をテストで固定)
UIのレイアウト調整(目視確認が主)
プロトタイプ・使い捨てスクリプト

コード例 — Python pytest

# tests/test_price_calculator.py

# --- サイクル1: 赤 ---
def test_calculate_tax_included_price():
    """税込み価格を計算する"""
    result = calculate_tax_included_price(1000, tax_rate=0.1)
    assert result == 1100

# --- サイクル1: 緑 ---
# price_calculator.py
def calculate_tax_included_price(base_price: float, tax_rate: float) -> float:
    return base_price * (1 + tax_rate)

# --- サイクル2: 赤 ---
def test_zero_price():
    """ 가격이 0이면 0을 반환 """
    result = calculate_tax_included_price(0, tax_rate=0.1)
    assert result == 0

# --- サイクル3: 赤 ---
def test_negative_price_raises():
    """ 음수 가격은 오류 """
    import pytest
    with pytest.raises(ValueError):
        calculate_tax_included_price(-100, tax_rate=0.1)
pytest tests/test_price_calculator.py -v

コード例 — TypeScript vitest

// src/priceCalculator.test.ts
import { describe, it, expect } from "vitest";
import { calculateTaxIncludedPrice } from "./priceCalculator";

describe("calculateTaxIncludedPrice", () => {
  it("税込み価格を計算する", () => {
    expect(calculateTaxIncludedPrice(1000, 0.1)).toBe(1100);
  });
  it("価格が0の場合は0を返す", () => {
    expect(calculateTaxIncludedPrice(0, 0.1)).toBe(0);
  });
  it("負の価格はエラー", () => {
    expect(() => calculateTaxIncludedPrice(-100, 0.1)).toThrow();
  });
});

// src/priceCalculator.ts
export function calculateTaxIncludedPrice(basePrice: number, taxRate: number): number {
  if (basePrice < 0) throw new Error("Price must be non-negative");
  return basePrice * (1 + taxRate);
}
npx vitest run

よくあるつまずき

つまずき解決策
「何をテストすればいいかわからない」入力と期待出力を1つ決める。1つでいい
「テストが多すぎて書くのが苦痛」テストしにくい = 設計が悪い可能性。関数を小さく分ける
「DBやAPIのテストはどう書く」DIPで外部依存を注入する(設計原則参照)
「プライベートメソッドは?」不要。公開API経由で検証する

組み合わせ

設計原則 — TDD→自然とSRP・DIP BDD — ユーザー視点のテスト クリーンアーキテクチャ — 各層を独立テスト 仕様駆動開発 — 仕様→テスト→実装
CLAUDE.md用プロンプト:
## 開発手法: TDD
- 実装の前にテストを書く(赤→緑→リファクタリング)
- 新機能追加時: まずテストを書き、テストが失敗することを確認してから実装
- バグ修正時: バグを再現するテストを先に書き、通るように修正
- テストツール: Python=pytest, TypeScript=vitest
← 開発手法セレクタに戻る ← ガイド一覧に戻る