前端自动化测试指南
自动化测试是前端工程化的核心环节,用于保障代码质量、防止回归错误 (Regressions) 并提升重构信心。
1. 测试金字塔与策略
1.1 测试层级
从下到上,成本越来越高,运行速度越来越慢:
- 单元测试 (Unit Testing):
- 对象: 独立的函数、类、组件。
- 特点: 运行快,隔离性强,专注于逻辑正确性。
- 工具: Jest, Vitest.
- 集成测试 (Integration Testing):
- 对象: 多个单元组合在一起的交互(如父子组件交互、Hook 与组件交互)。
- 特点: 模拟真实环境,性价比最高(Testing Trophy 理念推荐)。
- 工具: React Testing Library, Vue Test Utils.
- 端到端测试 (E2E Testing):
- 对象: 整个应用,模拟真实用户操作(点击、跳转、API请求)。
- 特点: 环境最真实,但运行慢、维护成本高。
- 工具: Cypress, Playwright.
1.2 静态分析 (Static Analysis)
在代码运行前通过工具检查潜在错误。
- ESLint: 检查语法和风格错误。
- TypeScript: 类型检查,防止类型相关的运行时错误。
- Prettier: 统一代码格式。
2. 常用测试工具链
2.1 Test Runners (测试运行器)
- Jest:
- Facebook 推出,大而全(内置断言、Mock、覆盖率)。
- 基于 Node.js 环境(JSDOM 模拟浏览器)。
- React 项目标配。
- Vitest:
- 由 Vue/Vite 团队推出。
- 与 Vite 共享配置,速度极快(ESM Native)。
- API 兼容 Jest,适合 Vite 项目。
2.2 Component Testing Utilities
- Testing Library (React/Vue/Angular):
- 核心理念: "测试你的软件的使用方式,而不是实现细节"。
- 推荐通过
getByRole,getByText查找元素,而非 CSS 选择器。
- Vue Test Utils: Vue 官方的底层测试库。
- Enzyme: (已过时) Airbnb 推出,允许深层访问组件内部状态,不推荐用于现代 React 测试。
2.3 E2E Tools
- Cypress:
- 开发者体验极佳,自带浏览器 GUI,调试方便。
- 运行在浏览器内部。
- Playwright:
- Microsoft 推出,支持所有现代浏览器内核 (Chromium, WebKit, Firefox)。
- 运行速度快,支持并行,支持多 Tab。
3. 核心概念与技巧
3.1 Mocking (模拟)
- Mock Function: 捕获函数调用(调用次数、参数)。
- Mock Module: 模拟第三方库或 API 请求,避免真实网络 IO。
javascript
// Jest/Vitest 示例
import axios from 'axios';
vi.mock('axios'); // 模拟模块
test('API call', async () => {
axios.get.mockResolvedValue({ data: 'hello' });
// ...
});3.2 TDD (测试驱动开发)
- Red: 写一个失败的测试。
- Green: 写最少量的代码让测试通过。
- Refactor: 重构代码,保持测试通过。
3.3 快照测试 (Snapshot Testing)
将组件渲染结果保存为字符串文件。如果不小心改坏了 UI 结构,快照对比会报错。
javascript
expect(component).toMatchSnapshot();4. 最佳实践 (Testing Library 风格)
- 避免测试实现细节:
- ❌ 不要测试
component.state.count === 1。 - ✅ 应该测试
screen.getByText('Count: 1')是否存在。
- ❌ 不要测试
- 以用户视角查询元素:
- 优先:
getByRole(button, textbox),getByLabelText,getByPlaceholderText. - 最后:
querySelector(class, id)。
- 优先:
- Mock 尽可能少的边界:
- 集成测试中尽量使用真实的子组件,而不是全部 Mock 掉。
- 使用 MSW (Mock Service Worker) 在网络层拦截请求,而不是 Mock
axios库本身。
5. 常见面试题
- Unit Test 和 E2E Test 的区别是什么?
- 如何测试一个异步请求?(async/await, waitFor)
- 什么是 Code Coverage (代码覆盖率)?100% 覆盖率是必须的吗?
- TDD 和 BDD (行为驱动开发) 的区别?