PlaywrightにおけるFixtureと共通関数(クラス)の使い分け

PlaywrightにおけるFixtureと共通関数(クラス)の使い分け

Playwrightのテスト設計において、Fixtureと共通関数(クラス)をどのように使い分けるべきかを解説します。Fixtureは決まった状態を再利用するテストに向いており、共通関数(クラス)は状態が変化するテストに適しています。本記事では、それぞれの特徴、適用シーン、メリット・デメリットを整理し、具体的なコード例を交えて分かりやすく解説します。
Clock Icon2025.02.18

はじめに

Playwrightを用いたテストの設計において、Fixtureと**共通関数(クラス)**のどちらを使うべきか迷う場面が多々あります。

  • Fixtureはテストごとに決まった状態のPageオブジェクトを提供する
  • 共通関数(またはクラス)は、状態を変化させながらテストを進めるのに適している

本記事では、それぞれの特徴や適用シーンを解説し、どのようなケースで使い分けるべきかを整理していきます。

Fixtureの特徴と適用シーン

Fixtureの概要

PlaywrightのFixtureは、テスト実行時に特定の状態を持つオブジェクト(Pageなど)を事前にセットアップし、
その状態をテスト間で再利用できる仕組みです。

Fixtureが適しているケース

  1. テストごとに決まった初期状態を保証したい場合

    • 例:ログイン済みの状態を前提としたテスト
    • 例:特定の設定が適用された管理画面のテスト
  2. セットアップのコストを削減したい場合

    • 毎回ログイン操作を行うのではなく、一度セットアップした状態を使い回せる
  3. データの一貫性を保ちたい場合

    • 例:DBのデータが固定されている環境で、常に同じ条件でテストを実施したい

Fixtureのメリット

  • 同じ状態の再利用ができるため、セットアップ時間を削減できる
  • テストごとに初期状態を保証できるため、安定したテストが可能
  • コードの再利用性が高い

Fixtureのデメリット

  • 状態を変更する必要があるテストには向かない
    • 例:ECサイトの購入フロー(カートに商品を追加 → 削除 → 追加)のように、状態が動的に変化するテストでは使いづらい
  • 複雑になりがち
    • 多くのFixtureを組み合わせると、どの状態がどこで設定されているのか把握しにくくなる

Fixtureの実装例

import { test as base } from '@playwright/test';

// 独自のFixtureを定義
const test = base.extend<{ loggedInPage: Page }>({
    loggedInPage: async ({ page }, use) => {
        await page.goto('/login');
        await page.fill('#username', 'test_user');
        await page.fill('#password', 'password123');
        await page.click('button[type="submit"]');
        await use(page);
    }
});

test('ログイン後のダッシュボード表示', async ({ loggedInPage }) => {
    await loggedInPage.goto('/dashboard');
    await loggedInPage.waitForSelector('h1');
});

共通関数(クラス)の特徴と適用シーン

共通関数(クラス)の概要

共通関数やクラスを使うことで、状態が変化するテストシナリオを柔軟に記述できます。

共通関数(クラス)が適しているケース

  1. テストごとに異なる状態を作りたい場合

    • 例:ECサイトのカート機能のテスト(商品追加→削除→購入)
    • 例:管理画面で設定を変更しながら動作確認するテスト
  2. 操作の流れをモジュール化したい場合

    • 例:ログイン処理を共通関数にして、複数のテストで利用する
  3. テストの柔軟性を重視したい場合

    • 状態の変化を伴うテストをFixtureではなく、明示的な関数として記述することで可読性を向上させる

共通関数(クラス)のメリット

  • 状態が変化するテストに適している
  • テストの自由度が高い
  • シンプルな構造で記述できるため、理解しやすい

共通関数(クラス)のデメリット

  • ディレクトリ構造や命名規則を統一しないとカオスになる
    • どの関数がどこにあるのか分かりにくくなる可能性がある
  • コードの重複が発生する可能性がある
    • Fixtureを適切に使えば再利用できるが、関数のコピペが増えるとメンテナンスコストが上がる

共通関数(クラス)の実装例

export class CheckoutFlow {
    constructor(private page: Page) {}

    async addToCart(itemId: string) {
        await this.page.click(`#add-to-cart-${itemId}`);
    }

    async proceedToCheckout() {
        await this.page.click('#checkout-button');
    }
}

test('商品購入のテスト', async ({ page }) => {
    const checkout = new CheckoutFlow(page);
    await checkout.addToCart('item123');
    await checkout.proceedToCheckout();
});

Fixtureと共通関数(クラス)の使い分けまとめ

項目 Fixture 共通関数(クラス)
状態の固定 向いている 向いていない
状態の変化を伴う処理 不向き 向いている
コードの管理 設計次第で複雑 シンプルになりやすい
初期状態の保証 できる できない
テストの柔軟性 低い 高い

まとめ

  • Fixture は「同じ状態を維持する」ことが重要なテストに適している。
    • 例:ログイン済みの状態、設定が固定された画面のテスト
  • 共通関数(クラス) は「状態を更新しながら進む」テストに適している。
    • 例:ECサイトの購入フロー、設定変更を伴うテスト
  • どちらを選ぶかは、テストの目的やメンテナンス性を考慮して決定する。

Playwrightのテスト設計を適切に行い、保守性の高いE2Eテストを構築していきましょう!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.