真实场景
Day 18 - Network Interception and Mocking
今日目标
- 掌握
page.route()。 - 能 mock 接口响应。
- 能测试异常、空数据、慢响应等场景。
学习时间安排(60–120 分钟)
| 时间 | 模块 | 做什么 |
|---|---|---|
| 0-20 分钟 | 核心概念与词汇 | 读概念表,重点理解 route 的三种处理方式。 |
| 20-45 分钟 | 官方文档阅读 | 读 Network 文档的 mocking 部分和 API 测试的 mock 章节。 |
| 45-75 分钟 | 实操练习 | 对列表页完成正常/空/500 三种 mock 测试。 |
| 75-105 分钟 | 示例代码改写 | 给现有测试加慢响应和异常场景用例。 |
| 105-120 分钟 | 复盘与作业 | 完成 mock 场景清单,完成今日问题。 |
核心概念与词汇
| English | 中文 | 场景用法 |
|---|---|---|
page.route() | 路由拦截 | Use it when you intercept matching requests and decide what to do with them. |
route.fulfill() | 伪造响应 | Use it when you return a mocked response without hitting the server. |
route.continue() | 放行请求 | Use it when you let the request proceed, optionally modified. |
route.abort() | 中止请求 | Use it when you simulate a failed or blocked request. |
| mock | 模拟 | Use it when you replace a real response with a controlled one. |
| stub | 桩 | Use it when you replace a service with a fixed response for testing. |
| intercept | 拦截 | Use it when you capture a request before it reaches the network. |
| empty state | 空状态 | Use it when you verify the UI's behavior with zero data. |
| error state | 错误状态 | Use it when you verify the UI's behavior when the backend fails. |
| slow response | 慢响应 | Use it when you simulate latency to test loading states. |
| wildcard pattern | 通配符匹配 | Use it when **/api/products matches any host prefix. |
学习材料
- 必读:[Network - Mock APIs](https://playwright.dev/docs/mock)
- 必读:[Network - Modify API responses](https://playwright.dev/docs/mock#modify-api-responses)(了解变体)
- 选读:[Network - Abort requests](https://playwright.dev/docs/network#abort-requests)
重点理解
Mock 示例:
await page.route('**/api/products', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'Mock Product' }
]),
});
});
模拟错误:
await page.route('**/api/products', async route => {
await route.fulfill({
status: 500,
body: 'Internal Server Error',
});
});
模拟延迟:
await page.route('**/api/products', async route => {
await new Promise(resolve => setTimeout(resolve, 1000));
await route.continue();
});
实操步骤
对一个列表页面做 3 种测试:
- 正常返回数据。
- 返回空数组。
- 返回 500 错误。
断言页面分别显示:
- 列表内容。
- Empty state。
- Error message。
示例代码
import { test, expect } from '@playwright/test';
test('shows empty state when no data', async ({ page }) => {
await page.route('**/api/products', route =>
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' })
);
await page.goto('/products');
await expect(page.getByText('No products yet')).toBeVisible();
});
test('shows error message when backend fails', async ({ page }) => {
await page.route('**/api/products', route =>
route.fulfill({ status: 500, body: 'Internal Server Error' })
);
await page.goto('/products');
await expect(page.getByText('Something went wrong')).toBeVisible();
});
常见坑
- mock 后不再有真实请求,误以为页面 bug 而其实是 mock 数据写错了。
- 通配符写窄了(如
https://api.example.com/products),请求带查询参数就拦不到。 - 用 mock 全部替代真实 E2E,导致真实接口回归没人管。
- mock 的响应结构和真实接口脱节,前端更新后测试全绿但线上全红。
- 忘记 mock 情况下测试跑的是真实接口,数据被污染。
今日产出
- 一个网络 mock 测试文件。
- 一份 mock 场景清单。
今日问题
page.route()解决什么问题?- Mock 是否能替代真实 E2E?
- 什么时候应该使用真实接口?
- 如何避免 mock 数据和真实接口脱节?
- Mock 慢响应能测试什么?
复盘要点
- Mock 的价值是“确定性”:空数据、错误、慢响应这些真实环境难造的场景,mock 一秒钟就绪。
- 分层策略:mock 用于前端状态覆盖,真实接口用于集成与端到端,两者都要有。
- mock 与契约脱节是最大风险,团队有接口契约文档时,mock 数据应来自契约样例。
AI 时代扩展:AI 辅助 Playwright 测试
新增概念
| English | 中文 |
|---|---|
| contract-based mock | 基于契约的 mock |
| scenario simulation | 场景模拟 |
| mock data generation | mock 数据生成 |
适用场景
让 AI 根据接口契约生成不同场景的 mock 响应体(正常/空/错误/慢),或者审查你的 mock 数据是否与真实接口结构一致。
可复用表达 / 提示词
这是接口契约:GET /api/products 返回 { id, name, price }[]。请生成正常、空、500 三种 mock 响应体和对应测试。
请审查我的 mock 数据是否与真实接口结构一致,找出字段名、类型、嵌套结构的差异。
追问加练
- AI 生成的 mock 数据如何验证和真实接口一致?
- 慢响应 mock 的延时设多少合适?依据是什么?
- 哪些场景下 mock 是唯一可行的测试手段?
今日作业
- 完成 3 种 mock 场景测试并跑通。
- 完成“mock 场景清单”:正常/空/错误/慢/未授权等至少 6 种。
- 让 AI 按你的接口契约生成 mock 数据,和真实响应对比修正。