LESSON 20分

TDDの基本

ストーリー

「テストケースの設計技法は分かったな。 次はテストの『書き順』について話そう」

松本先輩がホワイトボードに3色の円を描いた。

「Red, Green, Refactor。TDDの基本サイクルだ。 テストを先に書いてから実装する。 最初は違和感があるかもしれないが、 慣れると手放せなくなるぞ」


TDD(テスト駆動開発)とは

TDD(Test-Driven Development)は、実装コードを書く前にテストコードを書く開発手法です。Kent Beck が提唱しました。

Red-Green-Refactor サイクル

       ┌──────────────┐
       │    1. Red     │  失敗するテストを書く
       │   (赤)       │
       └──────┬───────┘
              │
              ▼
       ┌──────────────┐
       │   2. Green    │  テストを通す最小限の実装
       │   (緑)       │
       └──────┬───────┘
              │
              ▼
       ┌──────────────┐
       │  3. Refactor  │  コードを改善する
       │  (リファクタ) │
       └──────┬───────┘
              │
              └──→ 1 に戻る

TDDの実践:FizzBuzz

サイクル1: 数字をそのまま返す

1. Red: 失敗するテストを書く

typescript
// fizzbuzz.test.ts
import { fizzBuzz } from './fizzbuzz';

describe('fizzBuzz', () => {
  it('1 を渡すと "1" を返す', () => {
    expect(fizzBuzz(1)).toBe('1');
  });
});
テスト結果: ❌ FAIL
→ fizzBuzz 関数がまだ存在しない

2. Green: テストを通す最小限の実装

typescript
// fizzbuzz.ts
export function fizzBuzz(n: number): string {
  return String(n);
}
テスト結果: ✅ PASS

3. Refactor: 改善の余地なし → 次のサイクルへ

サイクル2: 3の倍数で Fizz

1. Red

typescript
it('3 を渡すと "Fizz" を返す', () => {
  expect(fizzBuzz(3)).toBe('Fizz');
});
テスト結果: ❌ FAIL → "3" が返ってきた

2. Green

typescript
export function fizzBuzz(n: number): string {
  if (n % 3 === 0) return 'Fizz';
  return String(n);
}
テスト結果: ✅ PASS

サイクル3: 5の倍数で Buzz

1. Red

typescript
it('5 を渡すと "Buzz" を返す', () => {
  expect(fizzBuzz(5)).toBe('Buzz');
});

2. Green

typescript
export function fizzBuzz(n: number): string {
  if (n % 3 === 0) return 'Fizz';
  if (n % 5 === 0) return 'Buzz';
  return String(n);
}

サイクル4: 15の倍数で FizzBuzz

1. Red

typescript
it('15 を渡すと "FizzBuzz" を返す', () => {
  expect(fizzBuzz(15)).toBe('FizzBuzz');
});

2. Green

typescript
export function fizzBuzz(n: number): string {
  if (n % 15 === 0) return 'FizzBuzz';
  if (n % 3 === 0) return 'Fizz';
  if (n % 5 === 0) return 'Buzz';
  return String(n);
}

3. Refactor: コードを改善

typescript
export function fizzBuzz(n: number): string {
  const isFizz = n % 3 === 0;
  const isBuzz = n % 5 === 0;

  if (isFizz && isBuzz) return 'FizzBuzz';
  if (isFizz) return 'Fizz';
  if (isBuzz) return 'Buzz';
  return String(n);
}

TDDのメリット

メリット説明
設計が改善されるテストしやすいコード = 疎結合なコード
テストカバレッジが高い全ての実装にテストが先行する
過剰設計を防ぐテストを通す最小限の実装から始める(YAGNI)
ドキュメントになるテストが仕様を表す
デバッグ時間が減るバグが入った時点で即座に気づく

TDDの注意点

注意点説明
学習コスト慣れるまで時間がかかる
全てに適用しないUIやプロトタイプには不向きな場合がある
テストの保守テストもコードであり、保守が必要
過度な依存TDDだけで品質が保証されるわけではない

TDDの3つの法則

Uncle Bob(Robert C. Martin)が提唱した TDD の3つの法則です。

1. 失敗するテストを書く前に、プロダクションコードを書いてはならない

2. 失敗する最小限のテスト以上のテストを書いてはならない
   (コンパイルエラーも失敗に含む)

3. 現在失敗しているテストを通す以上のプロダクションコードを
   書いてはならない

まとめ

項目ポイント
TDDの定義テストを先に書いてから実装する開発手法
基本サイクルRed(失敗テスト)→ Green(最小実装)→ Refactor(改善)
メリット設計改善、高カバレッジ、過剰設計防止
適用範囲ビジネスロジック、アルゴリズムに特に有効

チェックリスト

  • Red-Green-Refactor サイクルを説明できる
  • 簡単な関数でTDDを実践できる
  • TDDのメリットと注意点を理解した
  • TDDの3つの法則を説明できる

次のステップへ

TDDの基本を学んだら、次はカバレッジと品質指標について学びます。テストの量と質をどう測定するか理解しましょう。


推定読了時間: 20分