项目结构
Day 13 - Fixtures
今日目标
- 理解 fixture 是 Playwright Test 的核心机制。
- 学会使用内置 fixture 和自定义 fixture。
学习时间安排(60–120 分钟)
| 时间 | 模块 | 做什么 |
|---|---|---|
| 0-20 分钟 | 核心概念与词汇 | 读概念表,重点理解 fixture 的依赖注入和生命周期。 |
| 20-45 分钟 | 官方文档阅读 | 读 Test fixtures 文档的 intro 和内置 fixture 部分。 |
| 45-75 分钟 | 实操练习 | 创建 testUser fixture 并在测试中使用。 |
| 75-105 分钟 | 示例代码改写 | 把 beforeEach 里的测试数据迁移到 fixture。 |
| 105-120 分钟 | 复盘与作业 | 完成今日问题,记录 fixture 与 hook 的选择标准。 |
核心概念与词汇
| English | 中文 | 场景用法 |
|---|---|---|
| fixture | 测试夹具 | Use it when you describe reusable setup that is injected into a test as a parameter. |
base.extend() | 扩展测试对象 | Use it when you define custom fixtures on top of the built-in test. |
| dependency injection | 依赖注入 | Use it when you explain why { page } arrives in the test signature automatically. |
use() | 提供 fixture 值 | Use it when you pass a value into the test and run teardown after it. |
| built-in fixture | 内置夹具 | Use it when you refer to page, context, browser, request. |
| custom fixture | 自定义夹具 | Use it when you create project-specific fixtures like testUser or apiClient. |
| scope | 作用域 | Use it when you decide whether a fixture is per-test or per-worker. |
| teardown | 拆卸 | Use it when you clean up after the test finishes using the fixture. |
| override | 覆盖 | Use it when you replace a built-in fixture with your own setup. |
| test data | 测试数据 | Use it when you supply accounts, payloads, or config through fixtures. |
学习材料
- 必读:[Test fixtures](https://playwright.dev/docs/test-fixtures)
- 必读:[Built-in fixtures](https://playwright.dev/docs/test-fixtures#built-in-fixtures)
- 选读:[Worker-scoped fixtures](https://playwright.dev/docs/test-fixtures#worker-scoped-fixtures)
重点理解
内置 fixture:
pagecontextbrowserrequest
自定义 fixture 示例:
import { test as base } from '@playwright/test';
type MyFixtures = {
testUser: { username: string; password: string };
};
export const test = base.extend<MyFixtures>({
testUser: async ({}, use) => {
await use({ username: 'demo', password: 'password' });
},
});
实操步骤
创建:
fixtures/test-fixtures.ts
实现一个 testUser fixture,并在测试中使用。
示例代码
// fixtures/test-fixtures.ts
import { test as base, expect } from '@playwright/test';
export type TestFixtures = {
testUser: { username: string; password: string };
loggedInPage: void;
};
export const test = base.extend<TestFixtures>({
testUser: async ({}, use) => {
await use({
username: process.env.TEST_USER ?? 'demo',
password: process.env.TEST_PASSWORD ?? 'password',
});
},
loggedInPage: async ({ page, testUser }, use) => {
await page.goto('/login');
await page.getByLabel('Username').fill(testUser.username);
await page.getByLabel('Password').fill(testUser.password);
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/dashboard/);
await use();
},
});
export { expect };
测试中使用:
import { test, expect } from '../fixtures/test-fixtures';
test('view dashboard as logged in user', async ({ loggedInPage, page }) => {
await expect(page.getByText('Welcome')).toBeVisible();
});
常见坑
- fixture 里塞满业务逻辑,一个 fixture 承担十件事,难以复用。
- 在
use()之前 await 失败不写日志,报错无法定位。 - fixture 和 beforeEach 职责重叠,同一前置逻辑两处维护。
- 忽略 fixture 的 teardown,创建的数据永远不清理。
- 每个测试都 new 一个 Page Object 而不是通过 fixture 注入。
今日产出
- 一个自定义 fixture。
- 一个使用 fixture 的测试。
今日问题
- Fixture 解决什么问题?
page为什么能直接作为参数传入测试?- 自定义 fixture 适合放测试数据吗?
- Fixture 和 beforeEach 有什么区别?
- Fixture 过度复杂会带来什么问题?
复盘要点
- fixture 的本质是“带生命周期的依赖注入”:setup 在 use 前,teardown 在 use 后。
- 选择标准:需要返回值或组合复用选 fixture,纯执行流程选 beforeEach。
- 好的 fixture 名读起来像业务角色(testUser、adminUser),而不是技术变量(data1)。
AI 时代扩展:AI 辅助 Playwright 测试
新增概念
| English | 中文 |
|---|---|
| fixture design | 夹具设计 |
| test context abstraction | 测试上下文抽象 |
| role-based fixture | 角色化夹具 |
适用场景
让 AI 根据你的测试重复逻辑设计 fixture 结构,或者审查现有 fixture 的职责是否过重、teardown 是否缺失。
可复用表达 / 提示词
我的测试里反复出现「创建用户→登录→清理」三步,请设计一个 fixture 方案,说明每个 fixture 的职责和生命周期。
请审查这个 fixture,指出职责过重、缺少 teardown、可复用性差的问题。
追问加练
- AI 设计的 fixture 组合链太深会带来什么问题?
- 角色化 fixture(adminUser/普通 user)如何避免测试数据互相影响?
- AI 生成的 teardown 你如何验证它真的执行了?
今日作业
- 完成 testUser 和 loggedInPage 两个 fixture,跑通 2 条使用它们的测试。
- 写一页笔记:fixture 与 beforeEach 的选择标准(至少 3 条)。
- 让 AI 审查你的 fixture,重点检查 teardown 和职责划分。