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

Day 12 - Hooks and Test Organization

今日目标

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

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

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

核心概念与词汇

English中文场景用法
describe测试套件分组Use it when you group related tests under a readable suite name.
beforeEach每个用例前执行Use it when every test needs the same setup, like navigation.
afterEach每个用例后执行Use it when you clean up or capture state after each test.
beforeAll套件前执行一次Use it with caution when you set up shared state for a suite.
afterAll套件后执行一次Use it when you tear down shared resources after a suite.
test suite测试套件Use it when you refer to a group of tests in one describe or file.
setup前置准备Use it when you describe what must be true before a test runs.
teardown后置清理Use it when you describe cleanup after a test.
test independence测试独立性Use it when each test can run alone in any order.
shared state共享状态Use it when state leaks between tests and causes flakiness.
serial mode串行模式Use it when a group of tests must run in order (last resort).
nested describe嵌套分组Use it when you group suites by module and then by feature.

学习材料

  • 必读:[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