🧪 テスト駆動開発(TDD)
📖 定義
TDD(Test-Driven Development、テスト駆動開発)は、テストを先に書いてからそのテストを通過するコードを書く開発手法です。Red-Green-Refactorサイクルを繰り返し、コード品質を高め、バグを減らし、リファクタリングを安全にします。単体テストは個別の関数やコンポーネントを独立して検証するテストです。
🎯 簡単な比喩
設計図を先に描く
従来の開発
1. 家を建て始める
2. 完成後に点検
3. 問題発見 → 大きな修正が必要
4. コスト増加
TDD
1. 設計図を描く(テスト作成)
2. 設計図通りに建てる(コード作成)
3. 検証(テスト実行)
4. 改善(リファクタリング)
5. 安全で正確
⚙️ 動作原理
TDDサイクル (Red-Green-Refactor)
🔴 Red(失敗)
└─ テスト作成 → 失敗(コードなし)
🟢 Green(成功)
└─ 最小限のコード作成 → テスト成功
🔵 Refactor(改善)
└─ コード改善 → テスト依然成功
繰り返し → 段階的改善
💡 主な例
基本的なTDD例
// ========== 1. Red: テスト作成(失敗) ==========
test('add関数は2つの数値を足す', () => {
expect(add(2, 3)).toBe(5);
});
// FAIL - addが定義されていない
// ========== 2. Green: 最小限のコード(成功) ==========
function add(a, b) {
return a + b;
}
// PASS ✅
// ========== 3. Refactor: 改善(必要な場合) ==========
// コードが単純なので改善不要
Jestで単体テスト
// user.js
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
isValidEmail() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(this.email);
}
}
// user.test.js
describe('User', () => {
let user;
beforeEach(() => {
user = new User('田中太郎', 'tanaka@example.com');
});
test('有効なメールアドレスでtrueを返す', () => {
expect(user.isValidEmail()).toBe(true);
});
test('無効なメールアドレスでfalseを返す', () => {
user.email = 'invalid-email';
expect(user.isValidEmail()).toBe(false);
});
});
非同期テスト
test('非同期関数がデータを返す', async () => {
const data = await fetchData();
expect(data).toEqual({ name: 'John' });
});
モック
// 関数モック
const mockCallback = jest.fn(x => x * 2);
[1, 2, 3].forEach(mockCallback);
expect(mockCallback).toHaveBeenCalledTimes(3);
// モジュールモック
jest.mock('axios');
test('fetchUserはユーザーデータを返す', async () => {
axios.get.mockResolvedValue({ data: { id: 1 } });
const user = await fetchUser(1);
expect(user).toEqual({ id: 1 });
});
🤔 FAQ
Q1. TDDの利点は?
A:
利点:
1. バグ減少
2. 安全なリファクタリング
3. コード品質向上
4. ドキュメント化
5. 自信
欠点:
1. 初期時間投資
2. 学習曲線
3. テストメンテナンス
結論: 長期的に利益