Previous
Day 11 · Playwright Configuration
Next
Day 13 · Fixtures
项目结构
Day 1260-120 minutesPlaywright QA hands-on drill

第 12 天:Hooks 与测试组织

今日目标

  • 掌握 beforeEachafterEachdescribe
  • 学会组织测试文件和测试套件。

学习时间安排(60–120 分钟)

时间模块做什么
0-20 分钟核心概念与词汇读概念表,区分 beforeEach/beforeAll 的执行时机。
20-45 分钟官方文档阅读读 Writing tests 的 describe 和 hooks 部分。
45-75 分钟实操练习把前 10 天的测试按模块重组。
75-105 分钟示例代码改写抽取重复的前置步骤到 beforeEach。
105-120 分钟复盘与作业完成今日问题,检查测试是否相互独立。

核心概念与词汇

English中文场景用法
describe测试套件分组用于说明该术语在 Playwright 测试中的使用场景。
beforeEach每个用例前执行用于说明该术语在 Playwright 测试中的使用场景。
afterEach每个用例后执行用于说明该术语在 Playwright 测试中的使用场景。
beforeAll套件前执行一次Use it with caution when you set up shared state for a suite.
afterAll套件后执行一次用于说明该术语在 Playwright 测试中的使用场景。
test suite测试套件用于说明该术语在 Playwright 测试中的使用场景。
setup前置准备用于说明该术语在 Playwright 测试中的使用场景。
teardown后置清理用于说明该术语在 Playwright 测试中的使用场景。
test independence测试独立性用于说明该术语在 Playwright 测试中的使用场景。
shared state共享状态用于说明该术语在 Playwright 测试中的使用场景。
serial mode串行模式用于说明该术语在 Playwright 测试中的使用场景。
nested describe嵌套分组用于说明该术语在 Playwright 测试中的使用场景。

学习材料

  • 必读:[Writing tests - Test hooks](https://playwright.dev/docs/writing-tests#hooks)
  • 必读:[Writing tests - Tests in a file](https://playwright.dev/docs/writing-tests#tests-in-a-file)
  • 选读:[Serial mode](https://playwright.dev/docs/test-parallel#serial-mode)(了解但不优先使用)

重点理解

示例:

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

test.describe('Docs navigation', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/');
  });

  test('open intro page', async ({ page }) => {
    await page.getByRole('link', { name: 'Get started' }).click();
    await expect(page).toHaveURL(/intro/);
  });

  test('open docs page', async ({ page }) => {
    await page.getByRole('link', { name: 'Docs' }).click();
    await expect(page).toHaveURL(/docs/);
  });
});

注意:

  • beforeEach 适合每个测试都需要的前置动作。
  • 不要让测试依赖上一个测试执行结果。
  • beforeAll 要谨慎,因为共享状态可能污染测试。

实操步骤

把前 10 天的测试按模块整理:

tests/
  smoke.spec.ts
  navigation.spec.ts
  form.spec.ts

每个文件使用 describe 分组。

示例代码

// navigation.spec.ts
test.describe('Navigation', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/');
  });

  test.describe('from homepage', () => {
    test('go to docs', async ({ page }) => {
      await page.getByRole('link', { name: 'Docs' }).click();
      await expect(page).toHaveURL(/docs/);
    });

    test('go to api reference', async ({ page }) => {
      await page.getByRole('link', { name: 'API' }).click();
      await expect(page).toHaveURL(/api/);
    });
  });
});

常见坑

  • beforeAll 里创建数据,被并行测试抢用或互相删除。
  • 测试 A 创建的数据给测试 B 用,单独跑 B 时必挂。
  • hooks 里塞进大量逻辑,失败时不知道是 setup 挂了还是测试挂了。
  • 所有测试共用一个 describe,报告里看不出模块结构。
  • --grep 时忘记 describe 前缀,匹配不到想要的用例。

今日产出

  • 重构后的测试目录。
  • 至少一个 beforeEach 示例。

今日问题

  1. beforeEachbeforeAll 有什么区别?
  2. 为什么测试之间不能互相依赖?
  3. describe 的主要作用是什么?
  4. 测试文件按页面分好,还是按业务流程分好?
  5. Hooks 里放太多逻辑有什么风险?

复盘要点

  • hooks 的边界:重复的前置动作进 beforeEach,共享的昂贵资源才考虑 beforeAll。
  • 组织方式的判断标准:一个新同学看文件名和 describe 名,能不能猜到测试测什么。
  • 每加一个 hook 都问自己:这会让测试更难独立运行吗?

AI 时代扩展:AI 辅助 Playwright 测试

新增概念

English中文
test refactoring测试重构
suite structure套件结构
setup minimization前置最小化

适用场景

让 AI 帮你把平铺的测试重组成 describe 结构,或者审查 hooks 里是否有重复逻辑和隐藏依赖。

可复用表达 / 提示词

我的 3 个文件共 15 条测试,请按模块提出 describe 分组方案,并指出哪些前置步骤应放入 beforeEach。
请审查我的 hooks,指出哪些逻辑放入 beforeEach 有风险,以及测试间是否有隐藏依赖。

追问加练

  • AI 建议把登录放进 beforeEach,什么场景下这是错的?
  • 按页面分文件和按流程分文件,AI 通常怎么建议?你的项目适合哪种?
  • 重构后的测试还能单独运行吗?你如何验证?

今日作业

  • 完成测试目录重组,每个文件有 describe 分组。
  • 找出并删除测试间的数据依赖,保证任意单条可运行。
  • 让 AI 审查你的目录结构和 hooks,采纳合理建议并记录理由。

自检清单

Previous
Day 11 · Playwright Configuration
Next
Day 13 · Fixtures