Vitest 学习与实践总结:在 React + TypeScript 项目中快速上手单元测试
今天我用4个小时学习和实践了 Vitest 这个前端测试工具。主要是了解一下它是什么,怎么用,尤其是怎么在我们常用的 React + TypeScript 项目里用。下面是我学习的一个简单总结和记录。
一、Vitest 是个啥?
简单来说,Vitest 就是一个用来给代码做测试的工具,比如测试一个函数能不能正常工作,或者一个 React 组件显示得对不对。
它最大的特点是快,而且和 Vite 项目(我们现在用的项目构建工具)搭配起来特别方便,几乎不需要做太多额外的配置。
二、为啥要用它?(它的好处)
- 速度快:因为它用到了 Vite 的一些特性,每次跑测试的时候几乎不需要重新打包,所以感觉测试跑起来飞快,节省时间。
- 开箱即用:对于我们这种用 Vite 创建的 React+TS 项目,不用折腾太多配置就能直接用,很方便。
- 和 Jest 差不多:它的写法和用法和另一个流行的测试工具 Jest 很像,所以如果以前写过 Jest,学起来就非常容易。
三、在 React + TypeScript 项目里怎么用?
我跟着教程和文档,大概走了下面几个步骤:
1. 安装东西
首先在项目里安装了 Vitest 和另外一个用来测试 React 组件的库(叫 @testing-library/react),安装命令大概是这样的:
dart
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
2. 创建配置文件
在项目根目录创建了一个 vitest.config.ts 文件,进行一些简单配置,告诉 Vitest 要用哪个环境(比如 jsdom 来模拟浏览器环境)。
javascript
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
},
});
3. 写一个简单的测试例子
我学着给一个最简单的组件写测试。比如,我们有一个按钮组件 Button.tsx。
-
组件代码(Button.tsx) :
typescriptinterface ButtonProps { text: string; onClick: () => void; } export const Button = ({ text, onClick }: ButtonProps) => { return <button onClick={onClick}>{text}</button>; }; -
测试代码(Button.test.ts) :
在旁边创建一个测试文件,用来检查这个组件能不能正常显示文字,以及点击能不能生效。
javascript
import { describe, it, expect, vi } from 'vitest'; // 从vitest引入工具
import { render, screen, fireEvent } from '@testing-library/react'; // 引入React测试库
import { Button } from './Button'; // 引入要测试的组件
describe('Button 组件', () => {
it('应该在页面上正确显示文字', () => {
// 1. 渲染组件
render(<Button text="点击我" onClick={() => {}} />);
// 2. 在屏幕上找到包含"点击我"文字的元素
const buttonElement = screen.getByText('点击我');
// 3. 断言(期望)这个元素确实在文档里
expect(buttonElement).toBeInTheDocument();
});
it('点击按钮时应该调用传入的函数', () => {
// 1. 创建一个模拟函数,用来检查它有没有被调用
const mockClick = vi.fn();
// 2. 渲染组件
render(<Button text="点击我" onClick={mockClick} />);
// 3. 找到按钮
const buttonElement = screen.getByText('点击我');
// 4. 模拟一次点击事件
fireEvent.click(buttonElement);
// 5. 断言(期望)我们传入的模拟函数被调用了一次
expect(mockClick).toHaveBeenCalledTimes(1);
});
});
4. 运行测试
最后在 package.json 里加一个命令,然后运行它就能看到测试结果了。
json
// package.json
"scripts": {
"test": "vitest"
}
在终端里跑命令:
arduino
npm run test
如果测试通过了,终端里就会显示绿色的对勾,告诉你所有测试都成功了,看着很有成就感。
四、对于组件来说,应该测试哪些方面?
像用户一样思考
| 测试类型 | 关键问题 |
|---|---|
| ✅ 渲染测试 | 用户看到了什么? |
| ✅ 交互测试 | 用户操作后发生了什么? |
| ✅ Props 测试 | 不同输入下行为是否正确? |
| ✅ 条件渲染 | 内容是否在正确时机显示/隐藏? |
| ✅ 异步测试 | 数据加载后 UI 是否更新? |
-
@testing-library/react:用于渲染和查询 -
@testing-library/jest-dom:提供toBeInTheDocument()等断言 -
vi.fn()/vi.spyOn():模拟函数 -
waitFor/findBy:处理异步 -
userEvent(比fireEvent更真实)
具体场景
| 场景 | 推荐测试方式 |
|---|---|
| 按钮、输入框、卡片等 UI 组件 | 测试渲染 + 交互 |
| 表单组件 | 测试输入、验证、提交 |
| 模态框、下拉菜单 | 测试显示/隐藏、点击遮罩关闭 |
| 列表组件 | 测试数据渲染、空状态、加载状态 |
| 容器组件(带逻辑) | 模拟 API,测试数据流 |
| 自定义 Hook | 单独测试 Hook 行为(用 renderHook) |
四、总结
通过今天的学习,我感觉 Vitest 确实很简单易用,配置起来不麻烦,写测试的语法也很清晰。对于我们现在的项目来说,是一个很不错的选择。