第五部分:E2E 测试 · Level 3 进阶
从用户的视角测试完整用户路径,用 Playwright 模拟真实用户在浏览器中的操作,为测试项目TaskFlow 建立最后一道防线。
学习目标
为什么学习
单元测试能发现函数级别的 Bug,集成测试能发现模块协作的 Bug。但有些 Bug 只有真实用户在浏览器中操作才能发现:
页面加载顺序问题(JS 执行时机) 浏览器兼容性问题 网络请求竞态条件 真实用户交互流程
你将掌握
E2E 测试与单元测试、集成测试的区别 Playwright 安装与配置 元素定位器(Selectors) 编写完整的 E2E 测试 调试和报告
一、什么是 E2E 测试?
💡 比喻 · E2E 测试 = 试车
单元测试 = 测试发动机零件(活塞是否合格) 集成测试 = 测试发动机装配(活塞+曲轴是否配合) E2E 测试 = 试驾(发动机+变速箱+底盘一起工作) 你可以测试每一个零件都合格,但不上路,你怎么知道车真的能开?
E2E vs 单元测试 vs 集成测试
| 测试范围 | |||
| 运行环境 | |||
| 执行速度 | |||
| Bug 定位 |
⚠️ 重要:E2E 测试慢、不稳定、维护成本高。只测关键用户路径,不要测每一个细节。
二、Playwright vs Cypress vs Selenium
| 速度 | |||
| 多浏览器 | |||
| 自动等待 | |||
| 推荐场景 |
三、元素定位器(Selectors)
推荐的选择器
| Role | |||
| Label | |||
| Placeholder | |||
| Text | |||
| Test ID |
避免的选择器
| CSS 选择器 | |
| XPath | |
| 精确坐标 |
四、第一个 E2E 测试
TaskFlow 测试示例
// tests/taskflow.spec.ts
import { test, expect } from '@playwright/test'
test.describe('TaskFlow 核心功能', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/')
})
test('创建新任务', async ({ page }) => {
// 1. 点击"新建任务"按钮
await page.getByRole('button', { name: '新建任务' }).click()
// 2. 填写任务表单
await page.getByLabel('任务标题').fill('学习 Playwright')
await page.getByRole('button', { name: '保存' }).click()
// 3. 验证任务出现在列表中
await expect(page.getByText('学习 Playwright')).toBeVisible()
})
test('登录功能', async ({ page }) => {
await page.getByRole('link', { name: '登录' }).click()
await page.getByLabel('邮箱').fill('test@taskflow.com')
await page.getByLabel('密码').fill('password123')
await page.getByRole('button', { name: '登录' }).click()
await expect(page.getByText('欢迎回来')).toBeVisible()
})
})
Playwright 配置
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
},
})
运行测试
npx playwright test# 运行所有测试
npx playwright test --ui # 交互式 UI
npx playwright show-report # 查看报告
五、高级特性
自动等待
// 自动等待元素可见
await page.getByRole('button', { name: '提交' }).click()
// 显式等待
await expect(page.getByText('操作成功')).toBeVisible({ timeout: 10000 })
// 等待网络请求
await page.waitForResponse(response =>
response.url().includes('/api/tasks') && response.status() === 200
)
截图与录制
// 截图
await page.screenshot({ path: 'homepage.png', fullPage: true })
// 录制 trace(详细调试信息)
await page.context().tracing.start({ screenshots: true, snapshots: true })
// ... 执行操作 ...
await page.context().tracing.stop()
API 请求测试
test('API 请求测试', async ({ request }) => {
const response = await request.post('/api/tasks', {
data: { title: 'API 创建的任务' },
})
expect(response.status()).toBe(201)
const task = await response.json()
expect(task.title).toBe('API 创建的任务')
})
六、🤖 AI 实践
AI 实践 1:用 AI 生成 E2E 测试
Prompt 模板:
请为以下 React 组件生成 Playwright E2E 测试。
组件是一个登录表单,包含:
- 邮箱输入框
- 密码输入框
- 记住我复选框
- 登录按钮
- 点击登录后跳转到 /dashboard
- 错误提示
请生成使用 getByRole/getByLabel 的完整测试。
AI 实践 2:用 AI 设计 E2E 测试策略
请为 Next.js + Supabase 的 Todo 应用设计 E2E 测试策略。
应用功能:注册/登录、创建/编辑/删除任务、分类、截止日期、完成、筛选搜索
请给出:
1. 应该测试的关键路径(不超过 10 个)
2. 每个路径的测试用例
七、✅ QA Checklist
⬜ ⬜ ⬜ ⬜ ⬜ ⬜ ⬜
八、❓ 思考题
E2E 测试和单元测试各有什么优缺点?为什么 E2E 测试不能替代单元测试? 什么样的测试用例应该用 E2E?什么样的应该用单元测试? E2E 测试的"Flaky"(不稳定)问题如何解决? Playwright 的"自动等待"机制是如何工作的? 如何平衡 E2E 测试的覆盖率和维护成本?
九、推荐阅读
下一节预告
API 测试:REST API 验证
REST API 基础 API 测试 vs E2E 测试 Supabase API 测试 API 错误处理测试 TaskFlow API 测试实战
夜雨聆风