概要
テストは単なる「確認作業」ではない。
それは**“ソフトウェアが意図通りに動き続けるための設計支援ツール”**である。
JavaScriptにおいて、単体テストと統合テストをどう設計し、どう住み分けるかは、
- モジュール構造
- 責務の分離
- 副作用の制御
と密接に関係する。
本稿では、テスト戦略を設計レベルで分解し、単体/統合テストの役割・設計・判断基準を明確にしていく。
1. 単体テストの目的と設計指針
// math.ts
export const sum = (a, b) => a + b;
// math.test.ts
test('sum of 1 and 2 is 3', () => {
expect(sum(1, 2)).toBe(3);
});
- ✅ 関数単位で入力 → 出力が決まっているものに適用
- ✅ 副作用なし、外部依存なしの純粋な処理に対して有効
- ✅ リファクタリングの安全性を担保する
2. 統合テストの目的と設計指針
// API連携 + ストア更新 + UI描画の一連の動作を検証
test('user login flow', async () => {
render(<Login />);
userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
userEvent.click(screen.getByText('Login'));
await waitFor(() => {
expect(screen.getByText('Welcome')).toBeInTheDocument();
});
});
- ✅ 複数のモジュールを現実的な形で連結して検証
- ✅ 副作用(API、ストレージ、ルーティング)を含めて確認
- ✅ バグの再現性とシナリオレベルの担保に向いている
3. それぞれの役割と設計的な境界
項目 | 単体テスト | 統合テスト |
---|---|---|
対象 | 関数・クラス・モジュール単位 | 機能全体・ページ・画面遷移 |
副作用の有無 | 原則なし(MockやStubで分離) | 原則あり(実API or MSW/DB連携) |
検証粒度 | 小さい・ピンポイント | 大きい・ユースケースベース |
実装変更への耐性 | 高い(テスタブルな設計が前提) | 中程度(構造変更に影響を受けやすい) |
バグ検知力 | ロジック・境界値・例外に強い | 繋がりの不整合・想定外フローに強い |
4. 単体と統合を接続する設計:責務分離と依存制御
// usecase.ts
export function registerUser(apiClient, validator, userData) {
if (!validator(userData)) throw new Error('Invalid');
return apiClient.post('/register', userData);
}
- ✅ 単体テスト:validator と apiClient を Mock に差し替えて検証
- ✅ 統合テスト:DIで依存を差し替えず、実ロジックの流れを通す
5. テストの優先度とカバレッジ設計
- 重要なロジック・計算 → 単体テストで網羅
- ユーザーの操作フロー → 統合テストでシナリオ検証
- インフラとの接続部分 → モック or 実接続でエッジテスト
- ✅ 「すべてをテストする」のではなく、目的に応じた最小構成で安定を担保
- ✅ テストしやすさを基準に設計を見直すことが、テストコストと品質の両立につながる
設計判断フロー
① 関数の出力は入力に依存しているか? → 単体テスト
② モジュール間の接続部分に不安があるか? → 統合テスト
③ 外部依存は明示的か? → Mock可能なら単体、不可なら統合
④ ユーザー操作からのエンドツーエンド確認が必要か? → 統合テスト
⑤ 実装変更に強いテストが必要か? → 単体テストを重視
よくあるミスと対策
❌ 統合テストだけ書いて「落ちた原因が特定できない」
→ ✅ 統合 → 単体へと掘り下げて書く。階層別に分離して整備。
❌ 単体テストでMockを使いすぎて本番挙動と乖離
→ ✅ Mockは「契約が安定している依存」に限定する
❌ テストが通ってもバグが混入する
→ ✅ 「確認したい事実」に対してテストが明示的か確認する
結語
テストを書くことはゴールではない。
それは**“設計を洗練させ、変更に強く、意図を保証できるシステムを育てるための構造戦略”**である。
- 単体テストは、設計を明示し、モジュールを独立させる
- 統合テストは、現実のフローを通して一貫性を確認する
- どちらをいつ使うかは「テストしやすさ」ではなく「設計目的」で判断する
JavaScriptにおけるテスト戦略とは、
“確認のためではなく、進化するソフトウェアを支える設計基盤である。”