Playwright 并行、分片与重试
本章介绍 Playwright 的并行执行策略、分片运行和失败重试机制,帮助你高效运行大规模测试套件。
并行执行
Playwright 默认使用多个 Worker 进程并行运行测试,充分利用多核 CPU。
fullyParallel 配置
fullyParallel 控制同一文件内的测试是否并行执行。
实例
// 文件路径:playwright.config.ts
export default defineConfig({
fullyParallel: true, // 同一文件内的测试也并行运行
});
export default defineConfig({
fullyParallel: true, // 同一文件内的测试也并行运行
});
当 fullyParallel: false 时,同一文件内的测试串行执行,不同文件之间并行执行。
当 fullyParallel: true 时,所有测试完全并行(包括同一文件内的)。
workers 数量控制
实例
export default defineConfig({
// 使用 4 个 Worker
workers: 4,
// 本地使用默认值,CI 使用固定 2 个
workers: process.env.CI ? 2 : undefined,
// 单线程模式(方便调试)
workers: 1,
});
// 使用 4 个 Worker
workers: 4,
// 本地使用默认值,CI 使用固定 2 个
workers: process.env.CI ? 2 : undefined,
// 单线程模式(方便调试)
workers: 1,
});
串行测试
使用 test.describe.serial 强制同一组内的测试串行执行。
实例
// 串行执行——每个测试依赖前一个测试的结果
test.describe.serial('用户注册到登录', () => {
test('步骤1:注册', async ({ page }) => { /* ... */ });
test('步骤2:验证邮箱', async ({ page }) => { /* ... */ });
test('步骤3:登录', async ({ page }) => { /* ... */ });
});
test.describe.serial('用户注册到登录', () => {
test('步骤1:注册', async ({ page }) => { /* ... */ });
test('步骤2:验证邮箱', async ({ page }) => { /* ... */ });
test('步骤3:登录', async ({ page }) => { /* ... */ });
});
尽量避免使用串行测试,因为它破坏了测试隔离性。
如果测试需要按顺序执行,考虑将多个步骤合并到一个测试中。
局部并行控制
通过 test.describe.configure 可以控制单个分组的并行模式。
实例
test.describe('一组测试', () => {
test.describe.configure({ mode: 'serial' }); // 强制串行
// test.describe.configure({ mode: 'parallel' }); // 强制并行
test('A', async () => {});
test('B', async () => {});
});
test.describe.configure({ mode: 'serial' }); // 强制串行
// test.describe.configure({ mode: 'parallel' }); // 强制并行
test('A', async () => {});
test('B', async () => {});
});
Sharding 分片运行
分片(Sharding)将测试分散到多台 CI 机器上执行,缩短总体运行时间。
使用方式
# 机器 1:运行第 1/4 片 npx playwright test --shard=1/4 # 机器 2:运行第 2/4 片 npx playwright test --shard=2/4 # 机器 3:运行第 3/4 片 npx playwright test --shard=3/4 # 机器 4:运行第 4/4 片 npx playwright test --shard=4/4
合并分片报告
所有机器运行完毕后,合并生成的报告文件。
# 每台机器生成报告(不自动打开) npx playwright test --shard=1/4 --reporter=blob # 合并所有 blob 报告 npx playwright merge-reports --reporter=html ./all-blob-reports
GitHub Actions 中的分片配置
实例
# 文件路径:.github/workflows/playwright.yml
jobs:
test:
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
jobs:
test:
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
重试机制
重试(Retries)让失败的测试自动再次运行,缓解偶发的不稳定因素。
配置重试
实例
// 文件路径:playwright.config.ts
export default defineConfig({
// 本地不重试(快速反馈),CI 上重试 2 次
retries: process.env.CI ? 2 : 0,
});
export default defineConfig({
// 本地不重试(快速反馈),CI 上重试 2 次
retries: process.env.CI ? 2 : 0,
});
单个文件或分组设置重试
实例
// 对整个分组设置重试
test.describe.configure({ retries: 3 });
test.describe('不稳定的功能(需要多次重试)', () => {
test('测试 A', async ({ page }) => { /* ... */ });
test('测试 B', async ({ page }) => { /* ... */ });
});
test.describe.configure({ retries: 3 });
test.describe('不稳定的功能(需要多次重试)', () => {
test('测试 A', async ({ page }) => { /* ... */ });
test('测试 B', async ({ page }) => { /* ... */ });
});
重试策略
| 策略 | 说明 |
|---|---|
| CI 环境重试 | 本地不重试(quick feedback),CI 上重试 2-3 次 |
| Trace 收集 | 配合 trace: 'on-first-retry',只在重试时记录 Trace |
| 不滥用重试 | 重试不能掩盖真正的 Bug。如果某个测试频繁失败需要重试才通过,应该修复根本原因 |
