跳到主要内容

重试

简介

测试重试是一种在测试失败时自动重新运行测试的方法。当测试不稳定且间歇性失败时,这非常有用。测试重试在配置文件中配置。

失败

Playwright Test 在工作进程中运行测试。这些进程是操作系统进程,独立运行,由测试运行器协调。所有工作进程都具有相同的环境,并且每个工作进程都启动自己的浏览器。

考虑以下代码片段

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

test.describe('suite', () => {
test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });
test.afterAll(async () => { /* ... */ });
});

所有测试都通过时,它们将按顺序在同一个工作进程中运行。

  • 工作进程启动
    • beforeAll 钩子运行
    • first good 通过
    • second flaky 通过
    • third good 通过
    • afterAll 钩子运行

如果任何测试失败,Playwright Test 将丢弃整个工作进程以及浏览器,并启动一个新的工作进程。测试将在新的工作进程中继续,从下一个测试开始。

  • 工作进程 #1 启动
    • beforeAll 钩子运行
    • first good 通过
    • second flaky 失败
    • afterAll 钩子运行
  • 工作进程 #2 启动
    • beforeAll 钩子再次运行
    • third good 通过
    • afterAll 钩子运行

如果您启用重试,第二个工作进程将通过重试失败的测试开始,并从那里继续。

  • 工作进程 #1 启动
    • beforeAll 钩子运行
    • first good 通过
    • second flaky 失败
    • afterAll 钩子运行
  • 工作进程 #2 启动
    • beforeAll 钩子再次运行
    • second flaky 被重试并通过
    • third good 通过
    • afterAll 钩子运行

此方案非常适合独立测试,并保证失败的测试不会影响健康的测试。

重试

Playwright 支持测试重试。启用后,失败的测试将被重试多次,直到它们通过,或直到达到最大重试次数。默认情况下,失败的测试不会重试。

# Give failing tests 3 retry attempts
npx playwright test --retries=3

您可以在配置文件中配置重试

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
// Give failing tests 3 retry attempts
retries: 3,
});

Playwright Test 将按如下方式对测试进行分类

  • “通过” - 首次运行通过的测试;
  • “不稳定” - 首次运行失败,但在重试时通过的测试;
  • “失败” - 首次运行失败且所有重试都失败的测试。
Running 3 tests using 1 worker

✓ example.spec.ts:4:2 › first passes (438ms)
x example.spec.ts:5:2 › second flaky (691ms)
✓ example.spec.ts:5:2 › second flaky (522ms)
✓ example.spec.ts:6:2 › third passes (932ms)

1 flaky
example.spec.ts:5:2 › second flaky
2 passed (4s)

您可以使用 testInfo.retry 在运行时检测重试,这可以用于任何测试、钩子或 fixture。这是一个在重试前清除一些服务器端状态的示例。

import { test, expect } from '@playwright/test';

test('my test', async ({ page }, testInfo) => {
if (testInfo.retry)
await cleanSomeCachesOnTheServer();
// ...
});

您可以使用 test.describe.configure() 为特定测试组或单个文件指定重试。

import { test, expect } from '@playwright/test';

test.describe(() => {
// All tests in this describe group will get 2 retry attempts.
test.describe.configure({ retries: 2 });

test('test 1', async ({ page }) => {
// ...
});

test('test 2', async ({ page }) => {
// ...
});
});

串行模式

使用 test.describe.serial() 对依赖测试进行分组,以确保它们始终一起按顺序运行。如果其中一个测试失败,则所有后续测试将被跳过。组中的所有测试将一起重试。

考虑以下使用 test.describe.serial 的代码片段

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

test.describe.configure({ mode: 'serial' });

test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });

在不进行重试的情况下运行时,失败后的所有测试都将被跳过

  • 工作进程 #1
    • beforeAll 钩子运行
    • first good 通过
    • second flaky 失败
    • third good 完全被跳过

在进行重试的情况下运行时,所有测试都将一起重试

  • 工作进程 #1
    • beforeAll 钩子运行
    • first good 通过
    • second flaky 失败
    • third good 被跳过
  • 工作进程 #2
    • beforeAll 钩子再次运行
    • first good 再次通过
    • second flaky 通过
    • third good 通过
注意

通常最好使您的测试隔离,这样它们可以被高效地独立运行和重试。

在测试之间重用单个页面

Playwright Test 为每个测试创建一个隔离的 Page 对象。但是,如果您想在多个测试之间重用单个 Page 对象,您可以在 test.beforeAll() 中创建您自己的对象,并在 test.afterAll() 中关闭它。

example.spec.ts
import { test, type Page } from '@playwright/test';

test.describe.configure({ mode: 'serial' });

let page: Page;

test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});

test.afterAll(async () => {
await page.close();
});

test('runs first', async () => {
await page.goto('https://playwright.net.cn/');
});

test('runs second', async () => {
await page.getByText('Get Started').click();
});