使用 Vitest 和 Testing Library 进行 React 组件测试
将 Wire Vitest 集成到 Vite 中,放置行为测试用例,运行 watch 模式与 CI 的对比测试,并指示 AI 智能体遵循红绿验证循环。
Vitest 是一款快速且基于 Vite 的测试运行工具,如果你熟悉 Jest,使用起来会感觉很顺手——同时它还能与 React Testing Library 搭配使用,用于进行组件行为测试。本指南将介绍其设置方法、实用的红绿循环流程、文件结构,以及如何向 AI 编程助手给出清晰指令,使其能够有效协助而非造成混乱。
1. 项目设置
作为开发依赖项,安装常用的 React 测试套件:
npm install -D vitest jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
对于 Vite React 项目,需在 vite.config.ts 中向 Vitest 告知应用的相关信息,这样别名和插件才能与生产环境构建保持一致:
For a Vite React project, add Vitest to vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
setupFiles: ['./src/test/setup.ts'],
globals: true,
},
})
environment: 'jsdom' 可让代码在无需真实浏览器的情况下使用 DOM API。一个简单的设置文件会为每个测试套件一次性注册 jest-dom 匹配器:
import '@testing-library/jest-dom/vitest'
将该文件通过 Vitest 的 setupFiles 选项引入,这样像 toBeInTheDocument 和 toHaveAccessibleName 这样的断言就能在所有地方正常使用。
2. 推荐的工作流程
采用紧密循环的流程:功能设计 → 测试 → 实现 → 验证 → 重构。
- 理解功能需求——列出用户可见的行为及重要状态(加载中、成功、错误、为空、禁用)。注意那些需要模拟的 API 或浏览器限制,以确保测试结果具有确定性。
- 先编写测试代码——优先使用 React Testing Library 的查询功能;验证用户能观察到的结果,而非内部状态;通过
userEvent模拟点击和输入操作,以提升测试的真实性。
npx vitest run src/components/Button.test.tsx
During development:
用于本地反馈循环的观察模式:
npx vitest
Run the full suite
通过package.json中定义的npm脚本运行完整测试套件:
npm test
或在不使用观察模式的情况下进行一次性CI风格的测试:
npx vitest run
Check coverage when appropriate
在需要重点检查未测试分支时使用覆盖率分析:
npx vitest run --coverage
将覆盖率视为参考依据,而非虚荣的百分比——应优先选择有意义的断言,而非追求100%的覆盖率。
3. 测试结构
将测试与它们所保护的组件放在一起:
src/
├── components/
│ ├── LoginForm.tsx
│ └── LoginForm.test.tsx
├── hooks/
│ ├── useUser.ts
│ └── useUser.test.ts
├── pages/
│ ├── Dashboard.tsx
│ └── Dashboard.test.tsx
└── test/
├── setup.ts
└── mocks/
For a component, structure tests around behavior:
以用户操作结果而非方法名称来构建测试用例:
describe('LoginForm', () => {
it('allows a user to submit valid credentials', async () => {
// arrange
// act
// assert
})
it('shows validation errors for invalid input', async () => {
// ...
}) it('disables submission while logging in', async () => {
// ...
})
})
在不同的it代码块中分别处理正常流程、验证失败情况以及禁用或加载状态。当出现故障时,失败的测试用例标题应明确指出具体行为问题。尽量少使用重复的辅助函数;清晰易懂的重复代码结构远胜于那些隐藏设计意图的复杂测试装置。
4. 与AI编码助手协作
4. Vitest-agent prompt
将助手视为资深的React测试工程师来指导它:首先编写或更新失败的测试用例,再实施最小的改动,最后通过Vitest进行验证并做类型检查:
npx vitest run <target-test>
npx vitest run
npm run typecheck
npm run lint
要求它优先使用 Testing Library 的查询方法(如 getByRole、findByText)而非脆弱的 CSS 选择器,通过模拟网络边界来替代直接访问组件状态;当测试记录了有意的设计限制时,还需留下简短说明。
结束时的习惯
保持 Vitest 的配置与 Vite 一致,以便路径别名和插件能与生产环境匹配。在 CI 环境中优先使用 run 命令,而在本地则直接运行测试。随着新功能的添加逐步扩展测试套件,而非一次性进行全面重写。通过“先测试、再实现、最后验证”的循环,React 应用既能保持可重构性,又不会影响由 Vite 提供的快速反馈机制,而这正是 Vitest 最初吸引人的地方。