見出し画像

PlaywrightとCircleCIで自動テストを高速化:シャーディングの導入手順( for Windows)


はじめに


こんにちは。株式会社SHIFTの崎山と申します。
今回はPlaywrightで実装されたテストシナリオをCircleCI上でシャーディングして並列化する方法をご紹介します。

シャーディングについて


Playwrightのシャーディングとは、複数のマシンで同時にテストを実行し全体の実行時間を短縮する機能です。

シャーディングが必要なシーン

Playwrightは、1つのマシン上でもワーカープロセスを起動して並列実行してくれます。ただし、1つのマシン上で同時に実行できる数は実行環境のCPUコア数に依存するため、より多くのテストを並列化したい場合には複数のマシンで分割実行する必要があります。また、各テストシナリオの実行はそれなりにメモリも消費します。メモリが十分ではない環境で過度な並列実行をすると、システム全体のパフォーマンスが低下してしまうため、負荷分散の観点からもシャーディングが有効な場合もあります。

前提


  • Node.js:v18.17.0

  • Playwright:v1.33.0

  • CircleIC:v2.1(config.ymlバージョン)

  • OS:Windows(CircleCI Orb circleci/windows@5.0)
    ※今回はWindows環境を前提とした説明になります。

実行イメージ


.circleci/config.ymlの並列実行レベル parallelism で指定された数だけジョブ(executor)を起動してPlaywrightのテストを実行します。テストレポートはジョブ毎に出力されるため、すべてのテストが終了した後にマージします。ジョブ間でファイルを共有する必要があるため、テストレポートは共有のワークスペースに保存します。

Playwrightのシャーディング実行イメージ(筆者作成)

サンプルコード


CircleCI設定ファイル

version: 2.1 

orbs: 
  win: circleci/windows@5.0 

jobs: 
  run-test: 
    executor: 
      name: win/default 
    parallelism: 4
    steps: 
      - checkout 
      - run: 
          name: Install playwright and browser. 
          command: | 
            npm install 
            npx playwright install chrome 
      - run: 
          name: Create temporary directory. 
          command: New-Item "./tmp/.reports" -ItemType Directory -Force 
      - run: 
          name: Run test.
          command: | 
            $SHARD = 1 
            $SHARD += $env:CIRCLE_NODE_INDEX 
            npx playwright test --shard=$SHARD/$env:CIRCLE_NODE_TOTAL 
          when: on_success 
      - run: 
          name: Copy report. 
          command: Copy-Item -Path "./playwright-report/report*.zip" -Destination "./tmp/.reports" -Force 
          when: always 
      - persist_to_workspace: 
          root: ./tmp 
          paths: 
            - "*" 

  merge-reports: 
    executor: 
      name: win/default 
    steps: 
      - checkout 
      - run: 
          name: Install playwright. 
          command: npm install 
      - attach_workspace: 
          at: ./tmp 
      - run: 
          name: Merge reports. 
          command: | 
            npx playwright merge-reports --reporter=html ./tmp/.reports 
      - store_artifacts: 
          path: ./tmp/.reports 

workflows: 
  run-test-workflow: 
    jobs: 
      - run-test 
      - merge-reports: 
          requires: 
            - run-test

Playwright設定ファイル

レポートは後でマージするためバイナリで出力します。シャーディングして出力したファイル名は実行間で重複しないことが保証されており、出力ディレクトリとファイル名は特に指定する必要はありません。

export default defineConfig({ 
  // 省略 
  reporter: "blob", 
  // 省略 
});

サンプルコード解説


parallelism キーでジョブの並列実行数を指定します(2以上の値)。下記のコードでは4つの独立したexecutorで runt-test のジョブが実行されることになります。

jobs:
  run-test:
    executor:
      name: win/default
    parallelism: 4

Playwrightに --shard=x/y オプションを渡すことによりシャードモードで実行します。 CIRCLE_NODE_INDEX はCircleCI標準の環境変数で現在実行中のジョブのインデックス(0始まり)が設定されています。 CIRCLE_NODE_TOTAL は並列実行されるジョブの総数が設定されています。

      - run:
          name: Run test.
          command: |
            $SHARD = 1
            $SHARD += $env:CIRCLE_NODE_INDEX
            npx playwright test --shard=$SHARD/$env:CIRCLE_NODE_TOTAL

前段で作成しておいたディレクトリ./tmp/.reportsにテストレポートをコピーして、 persist_to_workspace でジョブ間で共有可能なワークスペースにアップロードします。

      - run:
          name: Copy report.
          command: Copy-Item -Path "./playwright-report/report*.zip" -Destination "./tmp/.reports" -Force
          when: always
      - persist_to_workspace:
          root: ./tmp
          paths:
            - "*"

attach_workspace で共有のワークスペースにアタッチして、Playwrightの merge-reports コマンドでレポートをマージします。オプションに --reporter=html を指定することによりバイナリのレポートをhtmlに変換して出力しています。最後に store_artifacts でマージ後のレポートをアーティファクトにアップロードします。

      - attach_workspace:
          at: ./tmp
      - run:
          name: Merge reports.
          command: |
            npx playwright merge-reports --reporter=html ./tmp/.reports
      - store_artifacts:
          path: ./tmp/.reports

気を付けること


同一ファイル内のテストは分割実行されない

Playwrightでは1つのファイルに記述された複数のテストシナリオはシャードに分割されません。並列実行したいテストシナリオは別ファイルに記述する必要があります。

テストが不安定になる場合がある

Playwrightのテストシナリオ間で依存関係やテスト対象の競合などがある場合、並列実行した際にテストが失敗する可能性が高まります。テストシナリオは独立していることが望ましいですが、どうしても直列実行する必要があるものは1つのファイルにまとめるなど検討しましょう。

そもそもシャーディングが必要か検討する

シャーディングでは複数のマシンを起動するためマシンの数だけコストがかかります。全体の実行時間は短縮されるためトータルのコストも抑えられるというロジックですが、各マシンの起動にかかるオーバーヘッド等も考慮が必要です。シャーディングを使用した場合のコストパフォーマンスを見て本当に必要か検討しましょう。

おわりに


本記事ではPlaywrightとCircleCIで自動テストをシャーディングして、実行時間を短縮する方法を解説しました。 大がかりな実装を行わずに、設定ファイルの変更だけでシャーディングを実現できる点も大きな魅力かと思います。
自動テストのパフォーマンスでお困りの方は、ぜひ本記事を参考にしてトライしてみてください。

参考


CircleCI - テスト分割と並列実行

CircleCI - ワークスペースによるジョブ間のデータ共有

Playwright - シャーディング

Playwright - レポーター


執筆者プロフィール:崎山泰央
SIerでSE、PGのキャリアを積んだ後、株式会社SHIFTに入社。現在は自動化アーキテクトとして、テスト自動化の設計と導入に従事。

お問合せはお気軽に

SHIFTについて(コーポレートサイト)

SHIFTのサービスについて(サービスサイト)

SHIFTの導入事例

お役立ち資料はこちら

SHIFTの採用情報はこちら

PHOTO:UnsplashGoogle DeepMind