# テストポリシー 全ての振る舞いの変更には対応するテストが必要であり、全てのバグ修正にはリグレッションテストが必要。 ## 原則 | 原則 | 基準 | |------|------| | Given-When-Then | テストは3段階で構造化する | | 1テスト1概念 | 複数の関心事を1テストに混ぜない | | 振る舞いを検証 | 実装の詳細ではなく振る舞いをテストする | | 独立性 | 他のテストや実行順序に依存しない | | 再現性 | 時間やランダム性に依存せず、毎回同じ結果 | ## カバレッジ基準 | 対象 | 基準 | |------|------| | 新しい振る舞い | テスト必須。テストがなければ REJECT | | バグ修正 | リグレッションテスト必須。テストがなければ REJECT | | 振る舞いの変更 | テストの更新必須。更新がなければ REJECT | | エッジケース・境界値 | テスト推奨(Warning) | ## テスト優先度 | 優先度 | 対象 | |--------|------| | 高 | ビジネスロジック、状態遷移 | | 中 | エッジケース、エラーハンドリング | | 低 | 単純なCRUD、UIの見た目 | ## テスト構造: Given-When-Then ```typescript test('ユーザーが存在しない場合、NotFoundエラーを返す', async () => { // Given: 存在しないユーザーID const nonExistentId = 'non-existent-id' // When: ユーザー取得を試みる const result = await getUser(nonExistentId) // Then: NotFoundエラーが返る expect(result.error).toBe('NOT_FOUND') }) ``` ## テスト品質 | 観点 | 良い | 悪い | |------|------|------| | 独立性 | 他のテストに依存しない | 実行順序に依存 | | 再現性 | 毎回同じ結果 | 時間やランダム性に依存 | | 明確性 | 失敗時に原因が分かる | 失敗しても原因不明 | | 焦点 | 1テスト1概念 | 複数の関心事が混在 | ### 命名 テスト名は期待される振る舞いを記述する。`should {期待する振る舞い} when {条件}` パターンを使う。 ### 構造 - Arrange-Act-Assert パターン(Given-When-Then と同義) - マジックナンバー・マジックストリングを避ける ## テスト戦略 - ロジックにはユニットテスト、境界にはインテグレーションテストを優先 - ユニットテストでカバーできるものにE2Eテストを使いすぎない - 新しいロジックにE2Eテストしかない場合、ユニットテストの追加を提案する ## テスト環境の分離 テストインフラの設定はテストシナリオのパラメータに連動させる。ハードコードされた前提は別シナリオで壊れる。 | 原則 | 基準 | |------|------| | パラメータ連動 | テストの入力パラメータに応じてフィクスチャ・設定を生成する | | 暗黙の前提排除 | 特定の環境(ユーザーの個人設定等)に依存しない | | 整合性 | テスト設定内の関連する値は互いに矛盾しない | | プロセス終了保証 | テストランナーにタイムアウトと強制終了を設定し、プロセスリークを防ぐ | ```typescript // ❌ ハードコードされた前提 — 別のバックエンドでテストすると不整合になる writeConfig({ backend: 'postgres', connectionPool: 10 }) // ✅ パラメータに連動 const backend = process.env.TEST_BACKEND ?? 'postgres' writeConfig({ backend, connectionPool: backend === 'sqlite' ? 1 : 10 }) ```