首页 / 文章 / 使用 Vitest 和 Testing Library 进行 React 组件测试

使用 Vitest 和 Testing Library 进行 React 组件测试

将 Wire Vitest 集成到 Vite 中,放置行为测试用例,运行 watch 模式与 CI 的对比测试,并指示 AI 智能体遵循红绿验证循环。

773 词

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. 推荐的工作流程

采用紧密循环的流程:功能设计 → 测试 → 实现 → 验证 → 重构。

  1. 理解功能需求——列出用户可见的行为及重要状态(加载中、成功、错误、为空、禁用)。注意那些需要模拟的 API 或浏览器限制,以确保测试结果具有确定性。
  2. 先编写测试代码——优先使用 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 最初吸引人的地方。