为何jest.spyOn引入单个函数时无法失效模块缓存?
Jest测试中模块方法Mock失效的问题及解决
问题场景
有以下模块代码:
mod1.js
const f = (_n) => console.info('a:', _n) || _n * 2 module.exports = { f }
初始mod2.js(导致测试失败)
const { f } = require('./mod1') const g = (_n) => 3 * f(_n) module.exports = { g }
测试文件
describe('mod2', () => { it('should check 1', () => { const { g } = require('../src/mod2') expect(g(2)).toEqual(12) }) it('should check 2', () => { const mod1 = require('../src/mod1') jest.spyOn(mod1, 'f').mockImplementation(_n => _n * 4) const { g } = require('../src/mod2') expect(g(2)).toEqual(24) }) it('should check 3', () => { const mod1 = require('../src/mod1') jest.spyOn(mod1, 'f').mockImplementation(_n => _n * 5) const { g } = require('../src/mod2') expect(g(2)).toEqual(30) }) })
运行测试时,第2、3个用例失败,g始终调用的是mod1.f的原始实现。
原因分析
Node.js(包括Jest)会对已加载的模块进行缓存。当mod2使用const { f } = require('./mod1')时,是直接把mod1.f的函数引用赋值给了本地变量f。后续通过jest.spyOn修改的是mod1导出对象上的f属性指向,而mod2里的本地f变量依然指向原始函数,所以mock不会生效。
解决方法
修改mod2.js,保留对mod1模块对象的引用,每次调用g时通过模块对象访问f:
const mod1 = require('./mod1') const g = (_n) => 3 * mod1.f(_n) module.exports = { g }
这样修改后,所有测试用例均可正常通过。因为每次调用g时,都会读取mod1对象上的f属性,而Jest的spy已经修改了该属性的指向,所以mock逻辑会生效。
内容的提问来源于stack exchange,提问作者alain
相关产品推荐
相关产品推荐

