integration-e2e-testing · diff
git:20260808.6f01c0a to git:20260809.e398e13
63 added, 115 removed. Audit A to A.
---
name: integration-e2e-testing
- description: 統合テストとE2Eテストを設計。モック境界と振る舞い検証ルールを適用。E2Eテスト、統合テスト作成時に使用。
+ description: 受理済みの振る舞いを観測可能な境界で証明する、最小限の統合/E2Eテストセットを選定・設計する。E2Eテストまたは統合テストの作成・レビュー時に使用。
---
# 統合テスト・E2Eテスト設計・実装ルール
- ## References
+ ## 参照資料
- - **[references/e2e-design.md](references/e2e-design.md)** — E2Eテスト設計原則(候補の性質、選定基準、候補の記録)
+ - **[references/e2e-design.md](references/e2e-design.md)** — PlaywrightによるE2Eテスト設計原則(候補の性質、選定基準、候補の記録)
- **[references/e2e-environment-prerequisites.md](references/e2e-environment-prerequisites.md)** — service-integration-e2eの環境前提条件(seed data、auth fixture、環境チェックリスト)。fixture-e2eには稼働中のサービスも実データベースも不要
- ## テスト種別と上限
+ ## テスト種別と選定
- | テスト種別 | 目的 | スコープ | 外部依存 | ファイル形式 | 機能あたり上限 | 実装タイミング |
- |-----------|------|---------|---------|-------------|--------------|--------------|
- | 統合 | in-processでのコンポーネント間連携を検証 | システムの部分的な統合(in-processモジュール、UIコンポーネントの場合はReact/TSではRTL+MSW) | モック または in-process | `*.int.test.ts` | 最大3件 | 実装と並行して作成 |
- | fixture-e2e | 決定論的フィクスチャを用いてブラウザ上でUIの振る舞いを検証 | UIフロー全体(モックバックエンド/フィクスチャ駆動の状態) | モック/フィクスチャのみ — ライブサービスなし | `*.fixture-e2e.test.ts` | 最大3件 | UI機能と並行して作成 |
- | service-integration-e2e | 起動済みのローカルスタックに対してクリティカルユーザージャーニーを検証 | サービスをまたいだシステム全体 | ローカルの実サービスまたはスタブ | `*.service-e2e.test.ts` | 最大1-2件 | 最終フェーズでのみ実行 |
+ | テスト種別 | 目的 | スコープ | 外部依存 | ファイル形式 | 実装タイミング |
+ |-----------|------|---------|---------|-------------|--------------|
+ | 統合 | in-processでのコンポーネント間連携を検証 | システムの部分的な統合(in-processモジュール。UIコンポーネントではReact/TSのRTL+MSWなど) | モックまたはin-process | `*.int.test.ts` | 実装と並行して作成 |
+ | fixture-e2e | 決定論的フィクスチャを用いてブラウザ上の振る舞いを検証 | モックバックエンドまたはフィクスチャ駆動の状態によるUIフロー全体 | モック/フィクスチャのみ — ライブサービスなし | `*.fixture-e2e.test.ts` | UI機能と並行して作成 |
+ | service-integration-e2e | 起動済みスタックだけが露呈できる契約を検証 | サービスをまたいだシステム全体 | ローカルの実サービスまたはservice-levelスタブ | `*.service-e2e.test.ts` | 必要なサービスが存在してから実行 |
**レーン選択(E2Eのみ)**:
- - ユーザー向けUIジャーニーのデフォルトレーンは **fixture-e2e** — 決定論的フィクスチャに対して実ブラウザを動かし、ユニット/統合テストでは検出できないバグ(ボタンが動作しない、状態が更新されない、ナビゲーションが壊れる等)を検出でき、インフラ準備なしにCIで実行可能
- - **service-integration-e2e** は、ジャーニーの正しさが安全にフェイクできない実サービス間の挙動(データ永続化、トランザクション整合性、外部サービスのコントラクト)に依存する場合のみ追加
-
- 2つのE2Eレーンの予算は独立して計上される — あるジャーニーに fixture-e2e があっても service-integration-e2e の予算は消費されず、その逆も同様。
+ - ユーザー向けUIジャーニーのデフォルトレーンは **fixture-e2e** — 決定論的フィクスチャに対して実ブラウザを動かし、ユニット/統合テストでは検出できないバグ(ボタンが動作しない、状態が更新されない、ナビゲーションが壊れる等)を検出でき、インフラ準備なしにCIで実行できる
+ - 証明義務がデータ永続化、トランザクション整合性、外部サービス契約などの実サービス間の振る舞いにある場合は **service-integration-e2e** を選択する
- **クリティカルユーザージャーニー**: 収益影響・法的要件・大多数のユーザーが日常的に利用する機能
+ 受理済みの証明義務から始め、各義務をその故障を露呈できる最も安価な境界に割り当て、重複するカバレッジを除き、残った個別の故障をすべてカバーする最小のセットを残す。テスト数はその証明義務から決める。ある機能について、特定のレーンにテストが1件もないことも妥当である。
## 振る舞い優先の原則
- ### 観測可能性チェック(全てYESで対象)
+ ### 候補のエビデンス
- | チェック | 質問 | NOの場合 |
- |---------|------|----------|
- | 観測可能 | ユーザーが結果を観測できるか? | 除外 |
- | システム文脈 | 複数コンポーネントの統合が必要か? | 除外 |
- | 自動化可能 | CI環境で安定実行できるか? | 除外 |
+ 統合/E2Eテストの候補は、次の情報を示す:
- ### Include/Exclude基準
+ - 受理済みの振る舞いが指定する境界での観測可能な結果
+ - 選択したレーンが実行するコンポーネントをまたぐ、実害のある故障
+ - その故障を再現できる自動テストハーネスまたは制御された環境
- **Include**: ビジネスロジック正確性、データ整合性、ユーザー可視機能、エラーハンドリング
- **Exclude**: 外部実接続、パフォーマンス指標、実装詳細、UIレイアウト
+ 単独で観測できる振る舞いはユニット/コンポーネント検証へ振り分ける。制御された環境を利用できない場合は、service-integration-e2eの証明前提として記録する。
+ ### 候補の振り分け
+
+ - ビジネスロジックの正確性、データ整合性、ユーザーが観測できる振る舞い、観測可能なエラーハンドリングは、その境界を必要とする場合に統合/E2Eの候補とする。
+ - 純粋な実装詳細とデータ変換はユニットテスト、性能に関する主張は性能検証、レイアウトだけの主張はビジュアルまたはUIチェックへ振り分ける。
+ - 外部契約自体が証明対象である場合は、service-levelスタブまたは制御されたローカルサービスで表現する。
+
## スケルトン仕様
### 必須スケルトン形式
- プロジェクトのテスト対象パターンに一致してコミットされるファイルは、そのテストランナー上で有効なままでなければならない。検出したフレームワークにおける最小の pending スイート(`describe` と `it.todo`、またはその同等物)を用い、テストフレームワークの import と必須コメントのみを含める。実装タスクが pending のケースを置き換え、実装と同時にアプリケーションの import・アサーション・フィクスチャ・モックセットアップを追加する。
+ プロジェクトのテスト対象パターンに一致してコミットされるファイルは、そのテストランナー上で有効なままでなければならない。検出したフレームワークにおける最小のpendingスイート(`describe`と`it.todo`、またはその同等物)を用い、テストフレームワークのimportと必須コメントのみを含める。実装タスクがpendingのケースを置き換え、実装と同時にアプリケーションのimport、アサーション、フィクスチャ、モックセットアップを追加する。
- 各テストに以下のアノテーションを含めること。
+ 各テストに以下の注釈を含めること。
```typescript
// AC: "[受入条件原文]"
- // ROI: [0-120] | ビジネス価値: [0-10] | 頻度: [0-10] | 法的要件: [0|1] | 欠陥検出力: [0-10]
- // 振る舞い: [トリガー] → [処理] → [観測可能な結果]
- // @category: core-functionality | integration | edge-case | ux | fixture-e2e | service-integration-e2e
+ // Behavior: [トリガー] -> [処理] -> [観測可能な結果]
// @lane: integration | fixture-e2e | service-integration-e2e
// @dependency: none | [コンポーネント名] | full-ui (mocked backend) | full-system
- // @complexity: low | medium | high
- // @real-dependency: [コンポーネント名](任意、テスト境界で非モックセットアップが指定された場合)
- it.todo('[AC番号]: [テスト名]')
+ // @real-dependency: [コンポーネント名](任意。テスト境界で非モックのセットアップを指定した場合)
+ // Primary failure mode: [実装後のテストを必ず失敗させる具体的なリグレッション]
+ // Proof obligation: [実装後のテストでアサートすべき境界と観測可能な状態]
+ // Verification items: [義務が満たされたことを示す観測結果]
```
**`@lane` 選択ルール**:
- - `integration` — in-processでのコンポーネント間連携、ブラウザを使用しない(例: React/TSではRTL+MSW、その他言語でも in-process のモジュール/ハンドラ統合)
- - `fixture-e2e` — モックバックエンド/フィクスチャ駆動の状態に対するブラウザレベルのUI検証。`@dependency` は通常 `full-ui (mocked backend)`
- - `service-integration-e2e` — 起動済みローカルサービスまたはスタブに対するブラウザレベルまたはエンドツーエンドの検証。`@dependency` は `full-system`
+ - `integration` — in-processでのコンポーネント間連携。ブラウザは使用しない(例: React/TSではRTL+MSW、その他の言語ではin-processのモジュール/ハンドラ統合)
+ - `fixture-e2e` — モックバックエンドまたはフィクスチャ駆動の状態に対するブラウザレベルのUI検証。`@dependency`は通常`full-ui (mocked backend)`
+ - `service-integration-e2e` — 起動済みのローカルサービスまたはスタブに対するブラウザレベルまたはエンドツーエンドの検証。`@dependency`は`full-system`
### Property注釈
```typescript
// Property: `[検証式]`
// fast-check: fc.property(fc.[arbitrary], (input) => [不変条件])
- it.todo('[AC番号]-property: [不変条件記述]')
```
- ## マルチステップユーザージャーニーの定義
-
- 以下の3条件を**すべて**満たす場合、その機能にはマルチステップユーザージャーニーが含まれる:
-
- 1. **2つ以上の異なるインタラクション境界**をユーザーゴール達成のために順番に通過する。何が境界に該当するかはシステムタイプによる:
- - Web: 異なるルート/ページ
- - モバイルネイティブ: 異なる画面/ビュー
- - CLI: 異なるコマンド呼び出しまたは対話型プロンプト
- - API: トランザクションを形成する異なるAPI呼び出し(例: 作成 → 確認 → 確定)
- 2. **ステップ間で状態が伝搬する** — あるステップで生成されたデータや実行されたアクションが、次のステップの受け入れや表示に影響する
- 3. **ジャーニーに完了ポイントがある** — ユーザーまたは呼び出し元が到達する最終状態(例: 確認ページ、保存されたレコード、API成功レスポンス、完了したワークフロー)
-
- ### ユーザー向け vs サービス内部の分類
-
- マルチステップジャーニーは予約スロット適用判定のために分類される:
-
- | 分類 | 条件 | 予約スロット適用 | 例 |
- |------|------|----------------|-----|
- | **ユーザー向け** | 人間のユーザーが直接ステップをトリガーし結果を観察する(UI、CLI、または直接的なAPIインタラクション経由) | 対象 — デフォルトで **fixture-e2e** の予約スロットに割り当て。ジャーニーの正しさが実サービス間の挙動に依存する場合のみ service-integration-e2e の予約スロットを追加 | Web購入フロー、CLIセットアップウィザード、モバイルオンボーディング |
- | **サービス内部** | バックエンドサービスがユーザーの直接操作なしにステップをトリガーする | 予約スロット対象外 — 統合テストを使用。フルシステム検証が妥当な場合は通常のROI > 50パスを通じた service-integration-e2e は引き続き有効 | 非同期ジョブパイプライン、サービス間saga、スケジュールバッチ処理 |
-
- この分類は予約スロットルールおよびE2Eギャップチェックに適用される。それ以外の選定はレーンごとのROIルール(後述)に従う。
-
- ### ROI計算
-
- ```
- ROI Score = Business Value × User Frequency + Legal Requirement × 10 + Defect Detection(範囲: 0–120)
- ```
-
- ROI Scoreは**同一テスト種別内での優先順位付け**に使用する(統合テスト同士、E2Eテスト同士)。テスト種別間の比較には使用しない。統合とE2Eの予算は独立して選択されるため、種別間比較は不要。
-
- スコアの入力値には以下のルールを適用する:
-
- | 入力 | 範囲 | 根拠のルール |
- |------|------|-------------|
- | ビジネス価値 | 0〜10 | 0 = ユーザー・ビジネス上の成果なし、10 = 収益、法務、安全性、主要な製品成果 |
- | 利用頻度 | 0〜10 | 観測済みの製品分析データまたはサンプリングしたtelemetryを範囲へ対応づけ、情報源を記録する。観測データがない場合に限り、名前を明記したstakeholderの見積もりを推測として使用する。それもなければ不明とする |
- | 法的要件 | 0または1 | 明記された要件、ポリシー、規制で振る舞いが必須の場合のみ1 |
- | 欠陥検出力 | 0〜10 | 0 = より低コストな境界ですでに証明済み、10 = このレーンだけが重大な失敗を検出可能 |
-
- ROI Scoreが高いほど、同一テスト種別内での優先度が高い。正規化や上限処理は行わず、生のスコアをそのまま順位付けに使用する。重複排除は候補自体を除外する別のステップであり、スコアは変更しない。同点の場合は、欠陥検出力、ビジネス価値の順に高い方を優先し、それも同じなら環境・保守コストが低い方を優先する。
-
- 必要な入力値が不明で、レーンの予算境界における選定結果が変わり得る場合は候補選定を止め、必要な利用状況、要件、境界の根拠を具体的に報告する。選定結果が変わらない場合は、不明点を記録して継続する。
-
- #### レーン別ROI閾値
-
- 2つのE2Eレーンは所有コストが大きく異なるため、独立した閾値を使用する。
-
- | レーン | ROI閾値 | 理由 |
- |------|---------|------|
- | fixture-e2e | ROI ≥ 20(予約スロット以外) | ハーネスが整備されていればコストは統合テストと同等。少数のテストで十分な場合に MAX 3 を低シグナルなテストで埋めてしまうことを避けるためのフロア(基準点) |
- | service-integration-e2e | ROI > 50(予約スロット以外) | 作成・実行・保守コストが統合テストの3〜10倍。他の方法では価値を立証できないジャーニーのみに使用 |
-
- 予約スロットのルールはレーンごとに適用され、閾値を上書きする(予約された候補はROIスコアに関わらず出力される)。予約スロット以外でフロアを下回る候補は出力されず、予算は意図的に未消化のまま残し、低価値なテストで埋めない。
+ ## テストセットの選定
- #### ROI計算例
+ 1. 根拠となる成果物またはタスクから、受理済みの振る舞いと記録済みの証明義務を読み取る。
+ 2. 義務ごとに、テストを失敗させるべき実害のある故障と、それを露呈する観測可能な状態を挙げる。
+ 3. 既存テストを検索する。同じ境界を実行し、その故障によって失敗する場合にのみ既存のカバレッジを再利用する。
+ 4. 義務を満たす最も狭いレーンに割り当てる:
+ - 単独の実行で振る舞いが露呈する場合はunit/component
+ - in-processのコンポーネント契約はintegration
+ - バックエンドを決定論的に扱えるブラウザ上の振る舞いはfixture-e2e
+ - 永続化、トランザクション、メッセージ、外部契約など、起動済みの境界でのみ故障が露呈するものはservice-integration-e2e
+ 5. 1つのシナリオで複数の義務を証明でき、アサーションと故障の対応が明確なままであれば統合する。セットアップや故障モードが異なる場合は別のシナリオにする。
+ 6. 残った義務をカバーする最小のセットだけを出力する。各スケルトンに、受理済みの振る舞い、主要な故障、証明義務、選択したレーン、モック境界を記録する。
- | シナリオ | BV | Freq | Legal | Defect | ROI Score | テスト種別 | 選択結果 |
- |----------|----|------|-------|--------|-----------|-----------|---------|
- | コア決済UIフロー | 10 | 9 | 1 | 9 | 109 | fixture-e2e | ユーザー向けジャーニーの予約ルールにより選択 |
- | 実決済サービスへのコア決済 | 10 | 9 | 1 | 9 | 109 | service-integration-e2e | 実サービス間の振る舞いでなければ正しさを検証できないため選択 |
- | DismissボタンによるUI状態更新 | 6 | 7 | 0 | 8 | 50 | fixture-e2e | fixture-e2e予算内で選択 |
- | 決済エラーメッセージ表示 | 5 | 4 | 0 | 7 | 27 | fixture-e2e | fixture-e2e予算の3枠目として選択 |
- | 任意フィルタの永続化 | 4 | 4 | 0 | 6 | 22 | fixture-e2e | 閾値は満たすが、スコアがより高い3候補で最大3枠が埋まるため不選択 |
- | 実プロバイダーへの決済リトライ | 8 | 3 | 0 | 7 | 31 | service-integration-e2e | service-integration-e2eの閾値未満 |
+ 受理済みの振る舞いとリポジトリの証明境界を基準に選定する。プロダクト分析や数値化した価値見積もりは不要である。根拠となる情報源とリポジトリのエビデンスを確認しても、受理済みの振る舞いまたは必要な契約が未確定の場合はエスカレーションする。
## 実装ルール
### Property-Based Test実装
Property注釈がある場合、fast-check必須:
- - `fc.assert(fc.property(...))` 形式で記述
+ - `fc.assert(fc.property(...))`形式で記述
- スケルトンの`// fast-check:`コメントをそのまま実装に反映
- 失敗ケース発見時は具体的なユニットテストとして追加(リグレッション防止)
### 振る舞い検証の実装
**振る舞い記述の検証レベル**:
| ステップ種別 | 検証対象 | 例 |
|-------------|---------|-----|
- | トリガー | Arrangeで再現 | API障害 → mockResolvedValue({ ok: false }) |
+ | トリガー | Arrangeで再現 | API障害 -> mockResolvedValue({ ok: false }) |
| 処理 | 中間状態または呼び出し | 関数呼び出し、状態変更 |
| 観測可能な結果 | 最終出力の値 | 戻り値、エラーメッセージ、ログ出力 |
- **判定基準**: 「観測可能な結果」がテスト対象の**戻り値またはモックの呼び出し引数**として検証されていれば合格
+ **合格基準**: 「観測可能な結果」がテスト対象の**戻り値またはモックの呼び出し引数**として検証されていれば合格
### 検証項目の決定ルール
| スケルトンの状態 | 検証項目の決定方法 |
|-----------------|-------------------|
- | `// 検証項目:` が列挙されている | 列挙された全項目をexpectで実装 |
- | `// 検証項目:` がない | 「振る舞い」記述の「観測可能な結果」から導出 |
- | 両方ある | 検証項目を優先、振る舞いは補足として使用 |
+ | `// Verification items:`が列挙されている | 列挙された全項目をexpectで実装 |
+ | `// Verification items:`がない | `Behavior`記述の「観測可能な結果」から導出 |
+ | 両方ある | 検証項目を優先し、振る舞いは補足として使用 |
### 統合テストのモック境界
- 最初に合致する行を採用する:
+ レビュー対象の主張に最初に合致する行を採用する:
| 条件 | 使用する境界 |
|---|---|
- | 外部アダプター、query、migration、service契約自体がテスト対象 | 実境界、または `service-integration-e2e` レーンでのservice-levelスタブ — モックは自身が代役を務める契約を証明できない |
+ | 外部アダプター、query、migration、service契約自体がテスト対象 | 実境界、または`service-integration-e2e`レーンのservice-levelスタブ — モックは自身が代役を務める契約を証明できない |
| 外部APIまたはネットワーク呼び出しがテスト対象でない | モック |
| テスト対象のコンポーネント間連携 | 実物のin-processコンポーネント |
| 呼び出し自体がテストの検証対象(例: ログ出力) | 検証可能なモック(`vi.fn()`) |
| 呼び出しもその対象もテスト対象でない | 実物、または無視 |
### E2Eテストの実行条件
**fixture-e2e**:
- - UI機能の実装フェーズと並行して実行(最後に先送りしない)
- - モックバックエンド/フィクスチャ駆動の状態を使用(`@dependency: full-ui (mocked backend)`)。ライブサービス不要
- - インフラ準備なしにCIで実行可能
+ - UI機能の実装フェーズと並行して実行する
+ - モックバックエンドまたはフィクスチャ駆動の状態を使用する(`@dependency: full-ui (mocked backend)`)
+ - 決定論的なフィクスチャのセットアップを用いてCIで実行する
**service-integration-e2e**:
- - 全コンポーネント実装完了かつローカルスタック起動後、最終フェーズでのみ実行
- - ローカルの実サービスまたはサービススタブを使用 — 検証対象コンポーネントに対して in-process モックは使用しない(`@dependency: full-system`)
+ - 全コンポーネントが実装され、ローカルスタックが起動した後の最終フェーズでのみ実行する
+ - ローカルの実サービスまたはservice-levelスタブを通して検証対象コンポーネントを実行する(`@dependency: full-system`)
## レビュー基準
### スケルトンと実装の整合性
| チェック | 不合格条件 |
|---------|-----------|
| Property検証 | Property注釈があるのにfast-check未使用 |
| 振る舞い検証 | 「観測可能な結果」に対応するexpectがない |
| 検証項目網羅 | 列挙された検証項目がexpectに含まれていない |
| モック境界 | 統合テストで内部コンポーネントをモック化 |
### 実装品質
| チェック | 不合格条件 |
|---------|-----------|
| AAA構造 | Arrange/Act/Assertの区切りが不明確 |
| 独立性 | テスト間で状態共有、実行順序依存 |
| 再現性 | 日時・乱数に依存し結果が変動 |
### 共有mutationに対する経路の同等性
- 複数の経路が同じmutationに到達する場合 — CLIの経路とHTTPハンドラ、スケジュールジョブと手動トリガー、バッチと単件エンドポイント — 4つの軸で比較する: 検証、分類、リソース上限、および read / parse / mutation / reporting の順序。
+ 複数の経路が同じmutationに到達する場合 — CLIの経路とHTTPハンドラ、スケジュールジョブと手動トリガー、バッチと単件エンドポイント — 4つの軸で比較する: 検証、分類、リソース上限、およびread / parse / mutation / reportingの順序。
- 差異を許可できるのは意図を決める出所のみ: 要件、Design Doc、ADR。テストはその判断の下流にある — 存在する振る舞いを記録するものなので、許容側の経路をカバーする既存テストはその bypass を許可するのではなく確認していることになる。差異が許可された後は、テストがそれが決定どおりに振る舞うことを検証する。
+ 差異を許可できるのは意図を決める出所のみ: 要件、Design Doc、ADR。テストはその判断の下流にある。存在する振る舞いを記録するものなので、許容側の経路をカバーする既存テストはそのbypassを許可するのではなく確認していることになる。差異が許可された後は、テストが決定どおりに振る舞うことを検証する。
- 許可する出所を持たない差異については、bypass を露呈させるテストを要求する: チェックをスキップする側の経路でmutationを実行し、そのスキップされたチェックが守っていた状態をアサートする。
+ 許可する出所を持たない差異については、bypassを露呈させるテストを要求する。チェックをスキップする側の経路でmutationを実行し、そのスキップされたチェックが守っていた状態をアサートする。
| チェック | 不合格条件 |
|---------|-----------|
| 検証の同等性 | 一方の経路が検証する入力を他方が未検証で受け入れており、その差異を許可する要件も契約もない |
| 分類の同等性 | 同じ失敗が経路によって異なる分類となり、呼び出し側が観測する内容が変わる |
| リソース上限の同等性 | 一方の経路がサイズ・件数・タイムアウトの上限を強制し、他方が省いている |
- | 操作順序の同等性 | read / parse / mutation / reporting の順序が経路間で異なり、検証前にmutationしたり永続化前に報告したりしうる |
+ | 操作順序の同等性 | read / parse / mutation / reportingの順序が経路間で異なり、検証前にmutationしたり永続化前に報告したりしうる |
| bypassのカバレッジ | 説明のつかない差異について、許容側の経路でmutationを実行するテストがない |