JavaScript测试关键在于选配工具与避坑:Jest兼容老项目,Vitest适配Vite;单元测试聚焦函数行为而非实现细节;集成测试用Testing Library抽象DOM;CI失败多因环境差异,需统一Node版本、控制时间与环境变量。

JavaScript 单元测试和集成测试不是“选不选”的问题,而是“怎么选、怎么配、怎么避坑”的问题。主流工具链已经很成熟,但直接套模板容易在 CI、异步断言、DOM 模拟或模块解析上卡住。
用 Jest 还是 Vitest?关键看你的构建环境
Jest 仍是兼容性最广的选择,尤其适合已有 Webpack + Babel 的老项目;Vitest 则更适合 Vite 项目,启动快、原生支持 ESM 和 top-level await,且 API 与 Jest 高度兼容,迁移成本低。
- 如果你用
vite,优先试vitest:配置少、HMR 测试热更新可用,vitest.config.ts里只需几行就能启用 DOM 测试 - 如果项目依赖
ts-jest或大量自定义transform,Jest 更稳妥,但要注意jest.config.cjs中transform规则必须显式匹配.ts和.tsx - Vitest 默认不模拟 Node.js 内置模块(如
fs),需手动用vi.mock('fs');Jest 则默认隔离并提供jest.mock('fs')
单元测试写什么?聚焦函数行为,而非实现细节
单元测试的核心是验证一个函数在给定输入下是否返回预期输出,或是否触发了预期副作用。别测“它有没有调用 fetch”,而要测“当 API 返回 200,它是否把数据塞进 state”。
- 对纯函数(如
sum(a, b)、parseDate(str)):直接传参、断言返回值,无需 mock - 对带副作用的函数(如 React 组件中的
handleClick):用vi.fn()或jest.fn()替换回调,再检查是否被调用及参数 - 避免测试私有方法或内部变量——它们属于实现细节,重构时会变;只测导出的函数或组件 props 接口
集成测试怎么跑真实组件?别硬扛 DOM,用渲染抽象层
直接操作 document 写集成测试极易断裂。应该用 @testing-library/react(React)或 @testing-library/vue(Vue)这类工具,它们封装了真实 DOM 渲染逻辑,并提供语义化查询(如 screen.getByRole('button'))。
立即学习“Java免费学习笔记(深入)”;
- 不要用
container.querySelector找元素——它绕过 React 更新队列,常导致“找不到刚渲染的节点” - 异步操作(如
fetch后更新 UI)必须用await waitFor(() => expect(...).toBeInTheDocument()),否则断言会跑在 DOM 更新前 - 测试组件交互时,用
userEvent.click()而非fireEvent.click(),前者模拟更完整(包括 focus、blur 等)
CI 里测试失败?先查环境差异,再查 mock 行为
本地通过、CI 失败,90% 是环境不一致导致:Node 版本、时区、系统 locale、甚至 process.env.NODE_ENV 值不同都会影响行为。
- 确保 CI 使用与本地一致的 Node 版本(在
.nvmrc或.node-version中声明) - 所有时间相关逻辑(如
new Date()、setTimeout)必须被vi.useFakeTimers()或jest.useFakeTimers()控制 - 避免在测试中读取未 mock 的环境变量;用
vi.stubEnv('API_BASE', 'https://test.example.com')显式控制
真正难的不是写第一个 it 块,而是让测试在团队协作、分支合并、CI 重跑时持续稳定——这取决于你对 mock 边界、异步时机和环境隔离的理解,而不是工具本身有多“高级”。











