Jest vs Vitest:React 开发者如何选择单元测试框架?
2024 年,GitHub 上 JavaScript 测试框架的下载量出现了一个微妙的分水岭。Jest 依然保持着统治地位,月下载量超过 2000 万次。但 Vitest 的增长曲线陡峭得吓人,过去一年下载量翻了四倍。如果你正在启动一个新 React 项目,大概率会在这两个框架之间犹豫。
先看本质区别
Jest 是 Meta 出品的测试框架,2014 年诞生,解决了当时 JavaScript 测试生态碎片化的问题。它自带断言库、mock 系统、覆盖率工具,开箱即用。Vitest 则是 2021 年底由 Anthony Fu 主导的开源项目,核心思路是复用 Vite 的生态和配置,用原生 ESM 运行测试。
两者最大的差异在底层架构。Jest 使用 Node.js 的 CommonJS 模块系统,测试文件需要经过 Babel 转译。Vitest 直接跑在 Vite 的 dev server 上,原生支持 ESM,不需要额外配置转译。
这个差异直接体现在速度上。在大型项目中,Vitest 的启动时间通常比 Jest 快 3 到 5 倍。我自己的一个项目,包含 400 多个测试文件,Jest 冷启动需要 6 秒,Vitest 只需要 1.2 秒。热更新场景下差距更明显,Vitest 几乎能做到即时反馈。
配置体验:Vitest 胜在简洁
Jest 的配置是出了名的繁琐。你需要安装 babel-jest、ts-jest 或者 @swc/jest 来处理 TypeScript,还要配置 moduleNameMapper 来映射路径别名,处理 CSS 和静态资源的 mock。一个典型 React 项目的 Jest 配置动辄五六十行。
Vitest 的配置几乎为零。如果你已经有 Vite 配置文件,直接在 vite.config.ts 里加一个 test 字段就行。路径别名、CSS 处理、静态资源导入,Vite 已经帮你搞定了。TypeScript 支持也是开箱即用的,不需要额外转译器。
// vite.config.ts
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
},
})
就这个对比,新项目用 Vitest 能省掉大量配置时间。
性能对比:不是同一个量级
性能是 Vitest 最直接的卖点。它利用了 Vite 的依赖预打包能力,node_modules 里的依赖会被预打包成 esbuild 格式,测试运行时不需要重复解析。Jest 则要逐个文件走 Babel 转译,速度自然慢。
社区里有一个经典的基准测试,来自 open source 项目 vite-plugin-pwa。在 1000 个测试用例的规模下,Vitest 完成全部测试耗时 3.2 秒,Jest 耗时 11.8 秒。差距接近 4 倍。
不过这里有个细节值得注意。Vitest 的快主要体现在 watch 模式和增量测试上。如果你只是跑一次完整测试就退出,两者的差距会缩小到 2 倍左右。CI 环境下,Jest 的 --maxWorkers 参数也能通过并行榨取一些性能。
生态兼容性:Jest 依然占优
Jest 十年的历史积累了大量生态工具。React Testing Library 的官方文档优先推荐 Jest。Testing Library 的 jest-dom matcher、user-event 等配套工具,对 Jest 的支持最完善。
Vitest 的兼容性做得不错,它实现了大部分 Jest 的 API,包括 jest.fn()、jest.mock() 这些,所以 Testing Library 的库基本能无缝迁移。但总有一些边缘情况。比如 jest.mock 的工厂函数作用域问题,Vitest 的 vi.mock 在 ESM 下行为略有不同,偶尔需要调整代码。
另一个差异在 snapshot 测试。Jest 的 snapshot 格式有十年的积累,社区里各种 prettier 插件和工具都支持它。Vitest 的 snapshot 格式基本兼容 Jest,但有些边界情况下的格式差异会让老项目迁移时产生大量 diff。
团队迁移成本:别只看表面
如果你的团队已经有大量 Jest 测试代码,迁移到 Vitest 的成本需要认真评估。大部分测试代码可以直接跑,但 jest.mock 的模块模拟机制在 Vitest 里可能遇到坑。Vitest 的 vi.mock 在 ESM 模式下对 hoisting 的处理更严格,有些写法需要调整。
一个真实的例子是 jest.mock('axios') 这种常见操作。在 Jest 里,mock 工厂函数可以引用外部变量,因为 Jest 会做变量提升。Vitest 的 ESM 实现不允许这样做,你需要把 mock 工厂函数内联或者使用 vi.hoisted()。这个改动虽然不大,但遇到大型测试套件时会增加不少工作量。
我的建议
新项目,尤其是已经使用 Vite 的 React 项目,直接选 Vitest。配置简单、速度快、体验现代,这些都是实打实的优势。
已有 Jest 项目,除非你被性能问题困扰得不行,否则没必要着急迁移。Jest 依然稳定可靠,生态最成熟,团队也熟悉。迁移的成本和风险不低,收益主要是速度提升,这个权衡需要你自己判断。
Vitest 正在快速追赶 Jest 的生态差距,但还没完全追上。如果你依赖某些 Jest 专属的插件或工具,迁移前先确认它们在 Vitest 里有没有替代方案。
测试框架的选择没有标准答案。关键是搞清楚自己的项目规模、团队熟悉度和现有代码基础,再做决定。