测试钩子 beforeEach 等
本教程共 59 篇 · 第 41 篇 · 更新于 2026-08-04 · 约 10 分钟阅读
41. 测试钩子 beforeEach 等
本节目标:学完能正确使用四种钩子(beforeEach、afterEach、beforeAll、afterAll),清楚它们各自在什么时机、什么范围执行。
Fixture(夹具)负责「准备环境」,Hook(钩子)负责「在固定时机插一段代码」。Playwright 提供四个钩子,名字直白得不用翻译。但用错范围,坑就来了。
四种钩子一览
beforeEach:每条测试前执行。afterEach:每条测试后执行。beforeAll:整个文件(或 group)的所有测试之前,执行一次。afterAll:整个文件(或 group)的所有测试之后,执行一次。
Note钩子是写在
test.下面的函数,比如test.beforeEach(...)。它们只在同一个文件、同一个describe块内生效。
每条测试前后的准备
最常见的是 beforeEach,保证每条测试都从干净状态开始:
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ page }) => {
await page.goto('https://github.com/login');
});
test('能填用户名', async ({ page }) => {
await page.getByLabel('Username').fill('user1');
});
test('能填密码', async ({ page }) => {
await page.getByLabel('Password').fill('pass1');
});
只跑一次的重活
有些事没必要每条都做,比如开一个共享页面、准备一批共享数据。用 beforeAll:
import { test, expect, type Page } from '@playwright/test';
let sharedPage: Page;
test.beforeAll(async ({ browser }) => {
sharedPage = await browser.newPage(); // 注意:这个页面不走内置 page 夹具
await sharedPage.goto('https://playwright.dev/');
});
test.afterAll(async () => {
await sharedPage.close(); // 自己开的,自己关
});
test('标题正确', async () => {
await expect(sharedPage).toHaveTitle(/Playwright/);
});
Warning
beforeAll里建的对象会被同文件的多条测试共享,一条测试改了状态,下一条就得跟着受影响。这也意味着测试不再彼此独立。所以这招只在「确实只需建一次、且各测试互不干扰」时才用。
钩子的生效范围
钩子受 describe 块约束。写在某个 describe 里的 beforeEach,只对那个块内的测试生效:
import { test, expect } from '@playwright/test';
test.describe('登录相关', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('显示登录框', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
});
});
在钩子里用夹具
钩子也能声明夹具,和测试一样方便。下面用的是第 39 章那个自定义的 settingsPage:
import { test } from './my-test'; // 带自定义夹具的 test
test.beforeEach(async ({ settingsPage }) => {
await settingsPage.switchToDarkMode();
});
还可以把注解写进钩子,比如移动端暂时跳过:
import { test } from '@playwright/test';
test.beforeEach(async ({ page, isMobile }) => {
test.fixme(isMobile, '移动端设置页暂不支持');
await page.goto('http://localhost:3000/settings');
});
执行顺序全景
结合夹具时,大致顺序是这样的:
- worker(工作进程)级夹具建起来。
- 跑
beforeAll。 - 每条测试:自动夹具 →
page等测试级夹具 →beforeEach→ 测试体 →afterEach→ 测试级夹具拆掉。 - 跑
afterAll。 - worker 级夹具在进程结束时才拆。
记住两条就够:自动夹具永远最先建,测试级夹具每条测试后就拆。
钩子还是夹具?
这是新手常纠结的。我的取舍:准备逻辑只服务于少数测试、且不需要清理,用钩子够快;如果多测试共用、还需要清理、想跨文件复用,就升级成夹具(第 37、39 章)。
Tip想让某段「每个测试前后」的逻辑全局生效,不必每个文件都写钩子——把它做成
auto: true的夹具(第 39 章)更省事。
常见翻车点
- 在
beforeAll里放了不该共享的状态,并行时互相污染。 - 把
afterEach的清理写成了afterAll,导致第一条测试污染了第二条。 - 钩子依赖的夹具忘了声明,报「fixture 不存在」。
钩子用好了是利器,用岔了就成隐式耦合。保持每条测试独立,钩子只做轻量准备,基本不会出事。
小结
四个钩子按执行频次分两对:beforeEach/afterEach 每条测试前后跑,beforeAll/afterAll 整组测试只跑一次。常见坑就那几个——beforeAll 别放共享状态、afterEach 和 afterAll 别搞混、夹具忘声明。记住:轻量准备用钩子,要复用要清理就上夹具。