第 11 章:测试与调试
11.1 测试策略概览
| 类型 | 工具推荐 | 测试目标 | 适用范围 |
|---|---|---|---|
| 单元测试 | Jest | 逻辑函数、API 方法 | 工具函数、状态管理 |
| 组件测试 | React Testing Library | UI 组件行为 | 表单、交互逻辑 |
| E2E 测试 | Playwright / Cypress | 整体页面流程 | 登录、购物车、导航流程 |
11.2 安装测试工具
npm install --save-dev jest @testing-library/react @testing-library/jest-dom babel-jest identity-obj-proxy
如果你使用 TypeScript,还需要:
npm install --save-dev ts-jest @types/jest
📄 项目结构建议:
/__tests__
└── index.test.js
/components
└── Button.test.js
11.3 配置 Jest(JavaScript 项目)
📄 jest.config.js
module.exports = {
testEnvironment: 'jsdom',
moduleNameMapper: {
'\.(css|scss)$': 'identity-obj-proxy',
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
📄 jest.setup.js
import '@testing-library/jest-dom/extend-expect';
11.4 示例:单元测试函数
📄 lib/sum.js
export function sum(a, b) {
return a + b;
}
📄 __tests__/sum.test.js
import { sum } from '../lib/sum';
test('adds numbers correctly', () => {
expect(sum(1, 2)).toBe(3);
});
11.5 示例:组件测试
📄 components/Button.js
export default function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
📄 components/Button.test.js
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
test('calls onClick when clicked', () => {
const handleClick = jest.fn();
const { getByText } = render(<Button onClick={handleClick}>Click</Button>);
fireEvent.click(getByText('Click'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
11.6 示例:测试 Next.js API 路由
📄 pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ name: 'Next.js' });
}
📄 __tests__/hello.test.js
import handler from '../pages/api/hello';
import { createMocks } from 'node-mocks-http';
test('returns name from API', async () => {
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toEqual({ name: 'Next.js' });
});
安装测试工具:
npm install --save-dev node-mocks-http
11.7 端到端测试(E2E)
使用 Playwright(推荐)
npx playwright install
📄 tests/example.spec.ts
import { test, expect } from '@playwright/test';
test('homepage has title and links to docs', async ({ page }) => {
await page.goto('http://localhost:3000');
await expect(page).toHaveTitle(/Next.js/);
});
执行测试:
npx playwright test
11.8 调试技巧
| 场景 | 方法 |
|---|---|
| 组件问题 | 使用 React DevTools |
| SSR 错误 | 查看终端输出或浏览器控制台 |
| 调试 API 路由 | console.log + Postman / curl |
| 启用 VSC 调试 | 配置 .vscode/launch.json |
| 页面渲染异常 | getServerSideProps、getStaticProps 加日志排查 |
11.9 CI 集成测试
常用平台如 GitHub Actions、Vercel 等都支持测试集成:
📄 .github/workflows/test.yml
name: Run Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Run Jest tests
run: npm test
✅ 小结
| 类型 | 工具 | 场景 |
|---|---|---|
| 单元测试 | Jest | 函数、逻辑、API |
| 组件测试 | React Testing Library | 交互组件 |
| E2E 测试 | Playwright | 用户行为、流程测试 |
| Mock 请求 | node-mocks-http | 模拟 req, res 对象 |
| 调试方式 | DevTools / Console | 浏览器端和服务端日志 |