4、Jest vs Vitest:两者对比、迁移成本分析、为什么我选择Vitest

说实话,每次新开一个Vue项目,选测试框架这件事总会让我纠结一阵子。

Jest是老牌劲旅,生态成熟,文档齐全。Vitest是新秀,快,而且和Vite天生一对。

到底选哪个?

我自己的项目里,两个都用过。踩过坑,也尝过甜头。今天咱们就掰开揉碎了聊聊。

4.1 核心差异:速度与兼容性

先看一张对比表,心里有个底:

对比维度 Jest Vitest
底层运行机制 Node.js + jsdom Vite + esbuild
启动速度 慢(需要完整编译) 快(利用esbuild预构建)
HMR(热更新) 不支持 原生支持
TypeScript支持 需要额外配置(ts-jest / babel) 开箱即用
Vue单文件组件支持 需要@vue/vue3-jest 通过@vitejs/plugin-vue原生支持
API兼容性 Jest原生API 兼容Jest API(describe/it/expect)
社区生态 非常成熟 快速成长中

看到这里,你可能觉得Vitest全面碾压。嗯,大部分场景下确实如此。

但别急,咱们得聊聊迁移成本。

4.2 迁移成本分析:从Jest到Vitest

如果你是从零开始,那直接选Vitest,零成本。

但如果你手里有个老项目,已经用Jest写了上百个测试用例,那迁移就得掂量掂量了。

我去年把一个中型Vue3项目从Jest迁移到Vitest,前后花了大概两天时间。说说我遇到的坑:

  • 全局变量问题:Jest里有些全局变量(比如jest.fn()),Vitest里要改成vi.fn()。虽然API基本一致,但得全局替换。
  • Mock路径差异:Jest的mock是自动提升的,Vitest需要手动处理一些路径别名。我在项目中用了@别名,折腾了一会儿。
  • 环境配置:Jest用jsdom,Vitest默认也是jsdom,但有些细微的差异。比如window对象的某些属性,Vitest更严格。

我的建议:如果你的测试用例少于200个,迁移成本可以接受。超过500个,建议先评估一下收益。说白了,如果项目快结束了,就别折腾了。

4.3 为什么我最终选择了Vitest

原因其实很简单:快,而且和Vue生态无缝衔接

你想想看,Vue3 + Vite 已经是官方推荐的技术栈了。测试框架如果还要单独搞一套配置,那不是自找麻烦吗?

Vitest可以直接复用Vite的配置,包括resolve.alias、plugins、define等等。这意味着:

  • 你不用再写一份jest.config.js
  • 你不用再折腾ts-jest或者babel
  • 你不用再为Vue单文件组件单独配置transform

举个例子,在Jest里配置Vue单文件组件支持,你得这样:

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.vue$': '@vue/vue3-jest',
    '^.+\\.ts$': 'ts-jest'
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
}

而在Vitest里,你只需要:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  test: {
    // 大部分配置继承自vite
    environment: 'jsdom'
  }
})

看到了吗?配置量直接砍半。

而且,Vitest的HMR体验是真的爽。你改一行代码,测试结果几乎瞬间更新。Jest的话,每次改完都得等几秒甚至十几秒重新跑一遍。

核心结论:如果你在用Vite构建项目,选Vitest。如果你还在用webpack,那Jest可能更稳妥。但说真的,2024年了,新项目谁还用webpack啊?

4.4 避坑指南:我曾经踩过的几个坑

嗯,这里得说说我实际遇到的一些问题,免得你走弯路。

  • 坑一:全局变量冲突。Vitest默认把测试文件放在全局作用域,如果你在tsconfig里配置了types: ['vitest/globals'],那describe、it这些就不用import了。但如果你同时装了@types/jest,就会冲突。解决办法:只保留一个类型声明。
  • 坑二:异步测试超时。Vitest默认超时是5000ms,如果你的组件渲染比较复杂(比如用了大量异步组件),建议调大:test('should render', async () => { ... }, 10000)。
  • 坑三:DOM环境差异。Vitest的jsdom版本和Jest的不完全一样。比如,Jest里window.scrollTo是存在的,Vitest里可能没有。解决办法:在setup文件里手动mock一下。

特别提醒:如果你用了很多第三方库的mock,迁移前先查一下这些库是否支持Vitest。我遇到过某个老版本的axios-mock-adapter在Vitest下行为异常,最后升级版本才解决。

4.5 我的最终建议

说了这么多,总结一下我的个人看法:

  • 新项目:无脑选Vitest。快、省心、和Vue生态完美融合。
  • 老项目(Jest):如果测试用例少于200个,迁移过来。多于500个,保持现状,别折腾。
  • 混合项目:其实Vitest可以兼容大部分Jest的语法,你可以逐步迁移,不用一次性全改。

最后说一句,工具是为人服务的。别为了炫技而迁移,也别因为懒惰而错过好工具。选最适合你当前项目的,就是对的。

下一章,咱们就正式开始用Vitest写第一个Vue组件测试了。准备好了吗?