--- name: integration-e2e-testing description: 受け入れ済みの振る舞いを観測可能な境界で証明する、最小限の統合/E2Eテストセットを選定・設計する。E2Eテストまたは統合テストの作成・レビュー時に使用。 --- # 統合テスト・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` | 実装と並行して作成 | | 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** を選択する 受け入れ済みの証明義務から始め、各義務をその失敗を検出できる最も安価な境界に割り当て、重複するカバレッジを除き、残った個別の失敗をすべてカバーする最小のセットを残す。テスト数はその証明義務から決める。ある機能について、特定のレーンにテストが1件もないことも妥当である。 ## 振る舞い優先の原則 ### 候補のエビデンス 統合/E2Eテストの候補は、次の情報を示す: - 受け入れ済みの振る舞いが指定する境界での観測可能な結果 - 選択したレーンが実行するコンポーネントをまたぐ、実害のある不具合 - その失敗を再現できる自動テストハーネスまたは制御された環境 単独で観測できる振る舞いはユニット/コンポーネント検証へ振り分ける。制御された環境を利用できない場合は、service-integration-e2eの証明前提として記録する。 ### 候補の振り分け - ビジネスロジックの正確性、データ整合性、ユーザーが観測できる振る舞い、観測可能なエラーハンドリングは、その境界を必要とする場合に統合/E2Eの候補とする - 純粋な実装詳細とデータ変換はユニットテスト、性能に関する主張は性能検証、レイアウトだけの主張はビジュアルまたはUIチェックへ振り分ける - 外部契約自体が証明対象である場合は、service-levelスタブまたは制御されたローカルサービスで表現する ## スケルトン仕様 ### 必須スケルトン形式 プロジェクトのテスト対象パターンに一致するファイルをコミットする場合、そのファイルはテストランナー上で有効な状態を保たなければならない。検出したフレームワークにおける最小のpendingスイート(`describe`と`it.todo`、またはその同等物)を用い、テストフレームワークのimportと必須コメントのみを含める。実装タスクがpendingのケースを置き換え、実装と同時にアプリケーションのimport、アサーション、フィクスチャ、モックセットアップを追加する。 各テストに以下の注釈を含めること。 ```typescript // AC: "[受入条件原文]" // Behavior: [トリガー] -> [処理] -> [観測可能な結果] // @lane: integration | fixture-e2e | service-integration-e2e // @dependency: none | [コンポーネント名] | full-ui (mocked backend) | full-system // @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` ### Property注釈 ```typescript // Property: `[検証式]` // fast-check: fc.property(fc.[arbitrary], (input) => [不変条件]) ``` ## テストセットの選定 1. 根拠となる成果物またはタスクから、受け入れ済みの振る舞いと記録済みの証明義務を読み取る。 2. 義務ごとに、テストが検出すべき実害のある不具合と、その検出に使える状態を挙げる。 3. 既存テストを検索する。同じ境界を実行し、その不具合で失敗する場合にのみ既存のカバレッジを再利用する。 4. 義務を満たす最も狭いレーンに割り当てる: - 単独の実行で振る舞いを確認できる場合はunit/component - in-processのコンポーネント契約はintegration - バックエンドを決定論的に扱えるブラウザ上の振る舞いはfixture-e2e - 永続化、トランザクション、メッセージ、外部契約など、起動済みの境界でしか失敗を検出できないものはservice-integration-e2e 5. 1つのシナリオで複数の義務を証明でき、アサーションと失敗の対応が明確なままであれば統合する。セットアップや失敗モードが異なる場合は別のシナリオにする。 6. 残った義務をカバーする最小のセットだけを出力する。各スケルトンに、受け入れ済みの振る舞い、主要な失敗、証明義務、選択したレーン、モック境界を記録する。 受け入れ済みの振る舞いとリポジトリの証明境界を基準に選定する。プロダクト分析や数値化した価値見積もりは不要である。根拠となる情報源とリポジトリのエビデンスを確認しても、受け入れ済みの振る舞いまたは必要な契約が未確定の場合はエスカレーションする。 ## 実装ルール ### Property-Based Test実装 Property注釈がある場合、fast-check必須: - `fc.assert(fc.property(...))`形式で記述 - スケルトンの`// fast-check:`コメントをそのまま実装に反映 - 失敗ケース発見時は具体的なユニットテストとして追加(リグレッション防止) ### 振る舞い検証の実装 **振る舞い記述の検証レベル**: | ステップ種別 | 検証対象 | 例 | |-------------|---------|-----| | トリガー | Arrangeで再現 | API障害 -> mockResolvedValue({ ok: false }) | | 処理 | 中間状態または呼び出し | 関数呼び出し、状態変更 | | 観測可能な結果 | 最終出力の値 | 戻り値、エラーメッセージ、ログ出力 | **合格基準**: 「観測可能な結果」がテスト対象の**戻り値またはモックの呼び出し引数**として検証されていれば合格 ### 検証項目の決定ルール | スケルトンの状態 | 検証項目の決定方法 | |-----------------|-------------------| | `// Verification items:`が列挙されている | 列挙された全項目をexpectで実装 | | `// Verification items:`がない | `Behavior`記述の「観測可能な結果」から導出 | | 両方ある | 検証項目を優先し、振る舞いは補足として使用 | ### 統合テストのモック境界 レビュー対象の主張に最初に合致する行を採用する: | 条件 | 使用する境界 | |---|---| | 外部アダプター、query、migration、service契約自体がテスト対象 | 実境界、または`service-integration-e2e`レーンのservice-levelスタブ — モックは自身が代役を務める契約を証明できない | | 外部APIまたはネットワーク呼び出しがテスト対象でない | モック | | テスト対象のコンポーネント間連携 | 実物のin-processコンポーネント | | 呼び出し自体がテストの検証対象(例: ログ出力) | 検証可能なモック(`vi.fn()`) | | 呼び出しもその対象もテスト対象でない | 実物、または無視 | ### E2Eテストの実行条件 **fixture-e2e**: - UI機能の実装フェーズと並行して実行する - モックバックエンドまたはフィクスチャ駆動の状態を使用する(`@dependency: full-ui (mocked backend)`) - 決定論的なフィクスチャのセットアップを用いてCIで実行する **service-integration-e2e**: - 検証対象のコンポーネントが存在し、そのテストが通すサービスが起動している最も早いフェーズで実行する - ローカルの実サービスまたはservice-levelスタブを通して検証対象コンポーネントを実行する(`@dependency: full-system`) ## レビュー基準 ### スケルトンと実装の整合性 | チェック | 不合格条件 | |---------|-----------| | Property検証 | Property注釈があるのにfast-check未使用 | | 振る舞い検証 | 「観測可能な結果」に対応するexpectがない | | 検証項目網羅 | 列挙された検証項目がexpectに含まれていない | | モック境界 | 統合テストで内部コンポーネントをモック化 | ### 実装品質 | チェック | 不合格条件 | |---------|-----------| | AAA構造 | Arrange/Act/Assertの区切りが不明確 | | 独立性 | テスト間で状態共有、実行順序依存 | | 再現性 | 日時・乱数に依存し結果が変動 | ### 共有mutationに対する経路の同等性 複数の経路が同じmutationに到達する場合 — CLIの経路とHTTPハンドラ、スケジュールジョブと手動トリガー、バッチと単件エンドポイント — 4つの軸で比較する: 検証、分類、リソース上限、およびread / parse / mutation / reportingの順序。 差異を許可できるのは意図を決める出所のみ: 要件、Design Doc、ADR。テストはその判断の下流にある。存在する振る舞いを記録するものなので、許容側の経路をカバーする既存テストはそのbypassを許可するのではなく確認していることになる。差異が許可された後は、テストが決定どおりに振る舞うことを検証する。 許可する出所を持たない差異については、bypassを検出するテストを要求する。チェックをスキップする側の経路でmutationを実行し、そのスキップされたチェックが守っていた状態をアサートする。 | チェック | 不合格条件 | |---------|-----------| | 検証の同等性 | 一方の経路が検証する入力を他方が未検証で受け入れており、その差異を許可する要件も契約もない | | 分類の同等性 | 同じ失敗が経路によって異なる分類となり、呼び出し側が観測する内容が変わる | | リソース上限の同等性 | 一方の経路がサイズ・件数・タイムアウトの上限を強制し、他方が省いている | | 操作順序の同等性 | read / parse / mutation / reportingの順序が経路間で異なり、検証前にmutationしたり永続化前に報告したりしうる | | bypassのカバレッジ | 説明のつかない差異について、許容側の経路でmutationを実行するテストがない |