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のテストを実行します。テストレポートはジョブ毎に出力されるため、すべてのテストが終了した後にマージします。ジョブ間でファイルを共有する必要があるため、テストレポートは共有のワークスペースに保存します。
サンプルコード
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 - ワークスペースによるジョブ間のデータ共有
お問合せはお気軽に
SHIFTについて(コーポレートサイト)
SHIFTのサービスについて(サービスサイト)
SHIFTの導入事例
お役立ち資料はこちら
SHIFTの採用情報はこちら
PHOTO:UnsplashのGoogle DeepMind