コンテンツにスキップ

2.3. E2Eテスト規定

このドキュメントは、E2E(End-to-End)テストの実装に関する具体的な規約を定めます。E2Eテストは、実際のユーザーのようにシステムを操作し、主要な機能がシナリオ通りに連携して動作することを保証します。

1. E2Eテストの定義と目的

  • 定義:
    • E2Eテストとは、アプリケーションをブラックボックスとして扱い、ユーザーインターフェース(UI)層からデータベースや外部サービスまで含めた、システム全体を通したワークフローを検証するテストです。
  • 目的:
    • ユーザーの主要な利用シナリオが、本番環境と限りなく近い状態で正しく機能することを保証します。
    • 複数のコンポーネントやサービスにまたがる、複雑なデータフローとビジネスプロセス全体の整合性を検証します。
    • フロントエンドとバックエンドが正しく連携していることを最終確認します。

2. E2Eテストのスコープ(対象範囲)

E2Eテストは、作成と維持に最もコストがかかるため、「広く浅く」実施し、ビジネス上クリティカルな、以下の主要シナリオに絞って作成します。

  • ユーザー認証フロー:
    • ユーザー登録 → ログイン → ログアウト
  • 主要な業務フロー:
    • (ECサイトの場合)商品検索 → カートに追加 → 購入手続き → 注文完了
    • (SNSの場合)投稿作成 → タイムラインでの表示 → 他ユーザーからの「いいね」やコメント
  • 決済フロー:
    • 決済情報の入力 → 外部決済ゲートウェイとの連携 → 決済完了
  • クリティカルな設定変更:
    • パスワード変更、重要な個人情報の更新など。

E2Eテストで検証すべきでないこと

_全てのUI要素の見た目(これはビジュアルリグレッションテストの領域)。 _ 全ての入力パターンやエッジケース(これは単体テストや結合テストでカバーすべき)。* 詳細なエラーメッセージの内容。

3. 推奨ツールとフレームワーク

E2Eテストは、主にWebブラウザを自動操作して行います。

  • Playwright (推奨):
    • Microsoftが開発するモダンなE2Eテストフレームワーク。単一のAPIでChromium, Firefox, WebKitをテスト可能。自動待機機能が強力で、不安定になりがちなテストを安定させやすいです。
  • Cypress:
    • 開発者体験に優れ、独自のGUI(テストランナー)でデバッグが容易なのが特徴です。
  • Selenium:
    • 最も歴史があり、多くの言語で利用できる、事実上の標準ツール。柔軟性が高い反面、環境構築やテストの記述が複雑になりがちです。

4. E2Eテストの実装パターン

4.1. Page Object Model (POM) の採用

  • 目的: UIの変更に対するテストコードの脆弱性を低減し、保守性を高めるために、Page Object Model (POM) パターンを全面的に採用します。
  • ルール:
    • アプリケーションの各ページ(または主要なコンポーネント)に対応する「ページオブジェクト」クラスを作成します。
    • ページ上のUI要素(セレクタ)と、それらの要素に対する操作(クリック、入力など)は、全てこのページオブジェクトクラス内にカプセル化します。
    • テストコードは、ページオブジェクトのメソッドを呼び出す形で記述し、セレクタやDOM構造に関する記述をテストコードから完全に排除します。

Page Object Model の例 (Playwright + TypeScript):

// LoginPage.ts (ページオブジェクト)
export class LoginPage {
    constructor(private readonly page: Page) {}

    // 要素のセレクタ
    private get usernameInput() {
        return this.page.locator('#username');
    }
    private get passwordInput() {
        return this.page.locator('#password');
    }
    private get loginButton() {
        return this.page.locator('button[type="submit"]');
    }

    // ページに対する操作
    async goto() {
        await this.page.goto('/login');
    }

    async login(username, password) {
        await this.usernameInput.fill(username);
        await this.passwordInput.fill(password);
        await this.loginButton.click();
    }
}

// login.spec.ts (テストコード)
test('should allow a user to log in successfully', async ({ page }) => {
    const loginPage = new LoginPage(page);
    const dashboardPage = new DashboardPage(page);

    await loginPage.goto();
    await loginPage.login('testuser', 'password123');

    // ログイン後のダッシュボードページのURLや要素を検証
    await expect(dashboardPage.page).toHaveURL('/dashboard');
    await expect(dashboardPage.welcomeMessage).toBeVisible();
});

5. 注意事項

  • 実行時間とコスト: E2Eテストは非常に遅く、実行コストが高いため、CIでの実行タイミングは慎重に検討します。
    • 推奨: 本番環境へのリリース前や、夜間バッチなど、実行頻度を限定したステージで実行する。Pull Requestごとに実行するのは避けるべきです。
  • テストデータの管理:
    • E2Eテストは、クリーンな初期状態のテストデータを必要とします。
    • テストの実行前に、API経由やDB直接操作で、必要なテストアカウントやデータを準備するステップを組み込む必要があります。
  • 不安定さ (Flakiness) との戦い:
    • E2Eテストは、非同期なUIの挙動やネットワークの遅延などにより、本質的に不安定(Flaky)になりやすいです。
    • Playwrightなどのモダンなツールが持つ自動待機機能を最大限に活用し、安易なsleep(固定時間待機)は避けてください。