首页 / Next.js 16 入门教程 / 测试策略

Next.js 16 入门教程

测试策略

本教程共 42 篇 · 第 32 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

Next.jsNext.js 16 入门教程测试VitestPlaywright单元测试E2E

32. 测试策略

本节目标:理解 Next.js 项目中的测试类型划分,学会配置 Vitest 和 Playwright,能独立编写单元测试和端到端测试。

测试类型概览

在 React 和 Next.js 中,常见的测试类型有五种:

  1. 单元测试:测试独立的函数、Hook 或组件
  2. 组件测试:关注组件的渲染和交互行为
  3. 集成测试:测试多个单元协同工作
  4. 端到端测试(E2E):模拟真实用户在浏览器中操作
  5. 快照测试:捕获组件输出,检测意外变更

不同类型测试的覆盖范围和成本不同。单元测试运行快、成本低;E2E 测试覆盖全面但运行慢。

关于异步服务端组件

Next.js 的 async Server Components 是 React 生态的新特性,目前部分工具还不完全支持。对于异步组件,推荐用 E2E 测试而非单元测试来覆盖。

Vitest 单元测试

Vitest 是现代化的测试框架,与 Vite 生态集成好、启动速度快,是 Next.js 单元测试的首选。

快速启动

用官方模板一键创建:

npx create-next-app@latest --example with-vitest with-vitest-app

手动配置

  1. 安装依赖:
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
  1. 创建配置文件:
// 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',
  },
})
  1. 添加测试脚本:
{
  "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.tstests/ 目录。

编写 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 测试

实用技巧

  1. 测试行为而非实现:关注用户看到什么,而不是组件内部怎么实现
  2. getByRole 优先:这最接近用户感知元素的方式
  3. 避免过度测试:不是覆盖率越高越好,维护测试也有成本
  4. 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% 覆盖率,先保证核心功能有测试覆盖,再逐步完善。