如何阻止Jest调用模块顶层函数或修改其实现避免测试报错
问题根本原因
你的写法不生效有两个核心原因:
- 执行顺序错误:当你调用
require('../calculator.js')加载模块时,Node.js会立即运行calculator.js内所有顶层代码,doSomething()在这一步就已经执行抛出错误了,你后续写的mock、spyOn操作都在模块加载完成后才执行,根本赶不上阻止这次调用。 - 原模块未导出
doSomething:你原代码的module.exports中只导出了add和somethingElse,并没有对外暴露doSomething,你试图修改Calc.doSomething本质是在操作一个undefined值,自然不可能生效。
解决方案
方案1:允许修改原代码(最推荐,侵入性极低)
直接在原模块的顶层调用处加环境判断,Jest运行时默认会把NODE_ENV设为test,测试环境下跳过doSomething执行即可:
// calculator.js修改后的代码 const add = (a, b) => { return a + b; } function doSomething(){ throw Error('dang I messed you up') } // 仅非测试环境执行 if (process.env.NODE_ENV !== 'test') { doSomething(); } module.exports = { add, doSomething // 记得补全导出,后续有需要也可以正常调用mock }
测试文件不需要特殊修改,直接引入即可正常测试:
const { add } = require('../calculator.js'); test('Adding two numbers', () => { expect(add(5, 5)).toStrictEqual(10) })
方案2:不允许修改原代码,全量mock模块
如果不能改动calculator.js源码,可以直接用jest全量mock整个模块,跳过原模块的顶层执行逻辑:
// 测试文件代码 // jest.mock会被jest提升到所有代码前优先执行,先mock再加载模块 jest.mock('../calculator.js', () => { return { add: (a, b) => a + b, doSomething: jest.fn(() => console.log('so much nope')) } }) const { add } = require('../calculator.js'); test('Adding two numbers', () => { expect(add(5, 5)).toStrictEqual(10) })
方案3:不允许修改原代码,同时要保留原模块其他逻辑
如果不想全量重写模块逻辑,可以借助rewire库修改模块内部的私有函数:
- 先安装依赖:
npm install rewire --save-dev - 测试文件写法:
const rewire = require('rewire'); // 先临时拦截指定错误,避免模块加载时直接崩溃 const originalError = global.Error; global.Error = jest.fn((msg) => { if (msg === 'dang I messed you up') return; return new originalError(msg); }); const calcModule = rewire('../calculator.js'); // 恢复Error原实现 global.Error = originalError; // 修改模块内部的doSomething实现,后续调用不会再报错 calcModule.__set__('doSomething', jest.fn(() => console.log('so much nope'))); const add = calcModule.add; test('Adding two numbers', () => { expect(add(5, 5)).toStrictEqual(10) })
内容的提问来源于stack exchange,提问作者Chance Smith
相关产品推荐
相关产品推荐

