Next.js 16 入门教程
测试策略
本教程共 42 篇 · 第 32 篇 · 更新于 2026-07-30 · 约 7 分钟阅读
Next.jsNext.js 16 入门教程测试VitestPlaywright单元测试E2E
32. 测试策略
本节目标:理解 Next.js 项目中的测试类型划分,学会配置 Vitest 和 Playwright,能独立编写单元测试和端到端测试。
测试类型概览
在 React 和 Next.js 中,常见的测试类型有五种:
- 单元测试:测试独立的函数、Hook 或组件
- 组件测试:关注组件的渲染和交互行为
- 集成测试:测试多个单元协同工作
- 端到端测试(E2E):模拟真实用户在浏览器中操作
- 快照测试:捕获组件输出,检测意外变更
不同类型测试的覆盖范围和成本不同。单元测试运行快、成本低;E2E 测试覆盖全面但运行慢。
关于异步服务端组件
Next.js 的 async Server Components 是 React 生态的新特性,目前部分工具还不完全支持。对于异步组件,推荐用 E2E 测试而非单元测试来覆盖。
Vitest 单元测试
Vitest 是现代化的测试框架,与 Vite 生态集成好、启动速度快,是 Next.js 单元测试的首选。
快速启动
用官方模板一键创建:
npx create-next-app@latest --example with-vitest with-vitest-app
手动配置
- 安装依赖:
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
- 创建配置文件:
// vitest.config.mts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths(), react()],
test: {
environment: 'jsdom',
},
})
- 添加测试脚本:
{
"scripts": {
"test": "vitest"
}
}
编写第一个测试
// app/page.tsx
import Link from 'next/link'
export default function Page() {
return (
<div>
<h1>首页</h1>
<Link href="/about">关于</Link>
</div>
)
}
// __tests__/page.test.tsx
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'
test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: '首页' })).toBeDefined()
})
运行 npm run test,Vitest 会监听文件变化自动重跑测试。
测试交互行为
import { render, screen, fireEvent } from '@testing-library/react'
test('点击按钮计数增加', () => {
render(<Counter />)
const button = screen.getByRole('button', { name: '增加' })
fireEvent.click(button)
expect(screen.getByText('计数: 1')).toBeDefined()
})
测试异步操作
import { render, screen, waitFor } from '@testing-library/react'
test('加载后显示数据', async () => {
render(<UserProfile userId="1" />)
await waitFor(() => {
expect(screen.getByText('用户名: 张三')).toBeDefined()
})
})
Playwright 端到端测试
Playwright 是微软开源的 E2E 测试工具,支持 Chromium、Firefox、WebKit 三大浏览器引擎。
安装配置
npm init playwright@latest
安装后会生成 playwright.config.ts 和 tests/ 目录。
编写 E2E 测试
// tests/home.spec.ts
import { test, expect } from '@playwright/test'
test('首页标题正确', async ({ page }) => {
await page.goto('http://localhost:3000')
await expect(page).toHaveTitle('我的应用')
})
test('导航到关于页面', async ({ page }) => {
await page.goto('http://localhost:3000')
await page.click('text=关于')
await expect(page).toHaveURL('http://localhost:3000/about')
})
test('表单提交流程', async ({ page }) => {
await page.goto('http://localhost:3000/contact')
await page.fill('input[name="email"]', 'test@example.com')
await page.fill('textarea[name="message"]', '这是一条测试消息')
await page.click('button[type="submit"]')
await expect(page.locator('.success-message')).toBeVisible()
})
运行测试
# 运行所有测试
npx playwright test
# 带 UI 模式(方便调试)
npx playwright test --ui
# 只运行特定浏览器
npx playwright test --project=chromium
MSW 做 API Mock
在测试中,我们不想依赖真实的后端接口。MSW(Mock Service Worker)可以拦截网络请求返回模拟数据:
// mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
])
}),
]
在 Vitest 中集成 MSW:
// setup.ts
import { setupServer } from 'msw/node'
import { handlers } from './mocks/handlers'
const server = setupServer(...handlers)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
测试策略建议
测试金字塔
/ E2E \ ← 少量,覆盖核心流程
/ 集成测试 \ ← 中等数量
/ 单元测试 \ ← 大量,覆盖细节
/__________________\
什么时候写什么测试
- 工具函数、Hooks:单元测试
- 表单验证逻辑:单元测试
- 页面渲染:组件测试
- 登录、支付等核心流程:E2E 测试
- 跨页面交互:E2E 测试
实用技巧
- 测试行为而非实现:关注用户看到什么,而不是组件内部怎么实现
- 用
getByRole优先:这最接近用户感知元素的方式 - 避免过度测试:不是覆盖率越高越好,维护测试也有成本
- CI 集成:把测试加入 GitHub Actions 等 CI 流程
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm test
- run: npx playwright test
测试是项目质量的保障。刚开始不用追求 100% 覆盖率,先保证核心功能有测试覆盖,再逐步完善。