You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 14:46:01