パフォーマンスチューニング
Playwrightパフォーマンスチューニング完全ガイド
Section titled “Playwrightパフォーマンスチューニング完全ガイド”Playwrightテストの実行速度を向上させ、リソース使用量を最適化する方法を詳しく解説します。
1. 並列テストの実行
Section titled “1. 並列テストの実行”基本的な並列実行設定
Section titled “基本的な並列実行設定”const { defineConfig } = require('@playwright/test');
module.exports = defineConfig({ // 並列実行するworkerの数 workers: process.env.CI ? 2 : 4,
// 完全に並列実行 fullyParallel: true,
// または、ファイル単位で並列実行 // fullyParallel: false,});プロジェクトごとの並列実行
Section titled “プロジェクトごとの並列実行”module.exports = defineConfig({ projects: [ { name: 'chromium', use: { browserName: 'chromium' }, }, { name: 'firefox', use: { browserName: 'firefox' }, }, { name: 'webkit', use: { browserName: 'webkit' }, }, ],
// 各プロジェクトが並列実行される fullyParallel: true,});Worker数の最適化
Section titled “Worker数の最適化”module.exports = defineConfig({ // CPUコア数に応じて自動決定 workers: undefined,
// または、明示的に指定 workers: process.env.CI ? 2 : require('os').cpus().length,
// 最大worker数を制限 workers: Math.min(4, require('os').cpus().length),});2. ヘッドレスモードの活用
Section titled “2. ヘッドレスモードの活用”ヘッドレスモードの設定
Section titled “ヘッドレスモードの設定”module.exports = defineConfig({ use: { // CI環境ではヘッドレスモード headless: process.env.CI ? true : false,
// または、常にヘッドレス headless: true, },});ヘッドレスモードのパフォーマンス比較
Section titled “ヘッドレスモードのパフォーマンス比較”// ヘッドレスモード: 約20-30%高速// ヘッド付きモード: デバッグに便利
// 開発環境: ヘッド付き// CI環境: ヘッドレス3. ブラウザコンテキストの再利用
Section titled “3. ブラウザコンテキストの再利用”コンテキストの共有
Section titled “コンテキストの共有”// 悪い例: 各テストで新しいコンテキストを作成test('テスト1', async ({ browser }) => { const context = await browser.newContext(); const page = await context.newPage(); // テスト処理... await context.close();});
// 良い例: フィクスチャでコンテキストを再利用const { test } = require('@playwright/test');
test('テスト1', async ({ page }) => { // コンテキストは自動的に再利用される await page.goto('https://example.com');});認証状態の再利用
Section titled “認証状態の再利用”module.exports = defineConfig({ projects: [ { name: 'setup', testMatch: /.*\.setup\.js/, }, { name: 'chromium', use: { storageState: 'playwright/.auth/user.json', }, dependencies: ['setup'], }, ],});4. テストの最適化
Section titled “4. テストの最適化”不要な待機を削減
Section titled “不要な待機を削減”// 悪い例: 不要な待機test('テスト', async ({ page }) => { await page.goto('https://example.com'); await page.waitForTimeout(5000); // 不要な待機 await page.getByRole('button').click();});
// 良い例: 自動ウェイトを活用test('テスト', async ({ page }) => { await page.goto('https://example.com'); // 要素が表示されるまで自動的に待機 await page.getByRole('button').click();});ネットワークリクエストの最適化
Section titled “ネットワークリクエストの最適化”test('ネットワークリクエストの最適化', async ({ page }) => { // 不要なリソースをブロック await page.route('**/*.{png,jpg,jpeg,gif,svg}', route => route.abort()); await page.route('**/*.{css}', route => route.abort());
await page.goto('https://example.com'); // 画像やCSSが読み込まれないため、高速化});キャッシュの活用
Section titled “キャッシュの活用”test('キャッシュの活用', async ({ context }) => { // キャッシュを有効化 const page = await context.newPage();
// 最初のアクセス await page.goto('https://example.com');
// 2回目のアクセス(キャッシュから読み込まれる) await page.goto('https://example.com');});5. テストデータの最適化
Section titled “5. テストデータの最適化”テストデータの事前準備
Section titled “テストデータの事前準備”// 悪い例: 各テストでデータを作成test('テスト1', async ({ page }) => { // APIでデータを作成(時間がかかる) await page.request.post('/api/users', { data: userData }); // テスト処理...});
// 良い例: セットアップでデータを準備// setup.spec.jstest('setup', async ({ page }) => { // 一度だけデータを作成 await page.request.post('/api/users', { data: userData }); // 認証状態を保存 await page.context.storageState({ path: 'playwright/.auth/user.json' });});
// test.spec.jstest('テスト1', async ({ page }) => { // セットアップ済みのデータを使用 await page.goto('https://example.com'); // テスト処理...});6. タイムアウトの最適化
Section titled “6. タイムアウトの最適化”タイムアウト設定の調整
Section titled “タイムアウト設定の調整”module.exports = defineConfig({ // テスト全体のタイムアウト timeout: 30 * 1000, // 30秒
// 各アクションのタイムアウト expect: { timeout: 5 * 1000, // 5秒 },
// プロジェクトごとに設定 projects: [ { name: 'chromium', timeout: 60 * 1000, // 60秒 }, ],});7. リソースの最適化
Section titled “7. リソースの最適化”不要なリソースのブロック
Section titled “不要なリソースのブロック”test('リソースの最適化', async ({ page }) => { // 画像、フォント、CSSをブロック await page.route('**/*.{png,jpg,jpeg,gif,svg,woff,woff2,css}', route => { route.abort(); });
await page.goto('https://example.com'); // ページの読み込みが高速化される});リソースの優先度設定
Section titled “リソースの優先度設定”test('リソースの優先度設定', async ({ page }) => { // 重要なリソースのみを読み込む await page.route('**/*', route => { const resourceType = route.request().resourceType(); if (resourceType === 'image' || resourceType === 'font') { route.abort(); } else { route.continue(); } });
await page.goto('https://example.com');});8. 実務での最適化パターン
Section titled “8. 実務での最適化パターン”パターン1: CI/CD環境での最適化
Section titled “パターン1: CI/CD環境での最適化”module.exports = defineConfig({ workers: process.env.CI ? 2 : 4, retries: process.env.CI ? 2 : 0,
use: { headless: true, // CI環境では常にヘッドレス video: 'retain-on-failure', // 失敗時のみ動画を保存 screenshot: 'only-on-failure', // 失敗時のみスクリーンショット },});パターン2: テストの分割
Section titled “パターン2: テストの分割”// 大きなテストを小さなテストに分割// 悪い例test('大きなテスト', async ({ page }) => { // 100行以上のテストコード});
// 良い例test.describe('機能テスト', () => { test('機能1', async ({ page }) => { // 短いテスト });
test('機能2', async ({ page }) => { // 短いテスト });});パターン3: テストの並列化戦略
Section titled “パターン3: テストの並列化戦略”module.exports = defineConfig({ // ファイル単位で並列実行 fullyParallel: true,
// または、テスト単位で並列実行 fullyParallel: false,
// 最大worker数 workers: 4,});9. パフォーマンス測定
Section titled “9. パフォーマンス測定”テスト実行時間の測定
Section titled “テスト実行時間の測定”test('実行時間の測定', async ({ page }) => { const startTime = Date.now();
await page.goto('https://example.com'); await page.getByRole('button').click();
const executionTime = Date.now() - startTime; console.log(`Execution time: ${executionTime}ms`);
// 実行時間が閾値以内であることを確認 expect(executionTime).toBeLessThan(5000);});メモリ使用量の監視
Section titled “メモリ使用量の監視”test('メモリ使用量の監視', async ({ page, context }) => { const initialMemory = process.memoryUsage().heapUsed;
await page.goto('https://example.com'); // テスト処理...
const finalMemory = process.memoryUsage().heapUsed; const memoryIncrease = finalMemory - initialMemory;
console.log(`Memory increase: ${memoryIncrease / 1024 / 1024}MB`);});10. よくある問題と解決策
Section titled “10. よくある問題と解決策”問題1: テストが遅い
Section titled “問題1: テストが遅い”解決策:
- 並列実行を有効化
- 不要なリソースをブロック
- タイムアウトを最適化
- テストデータの準備を最適化
問題2: メモリ使用量が多い
Section titled “問題2: メモリ使用量が多い”解決策:
- コンテキストを適切に閉じる
- 不要なページを閉じる
- キャッシュをクリア
test.afterEach(async ({ page, context }) => { // テスト後にクリーンアップ await page.close(); await context.close();});問題3: CI環境でタイムアウトが発生する
Section titled “問題3: CI環境でタイムアウトが発生する”解決策:
- タイムアウトを適切に設定
- リトライを有効化
- ネットワークリクエストを最適化
これで、Playwrightのパフォーマンスチューニング方法を理解できるようになりました。