如何mock模块级实例,验证myFunction是否调用了logger.log方法
错误原因分析
第一个方案失败原因
- 业务代码中
logger是在模块顶层作用域初始化的,当你导入被测试模块时,new Logger()就已经执行完成。你在测试用例内部才修改mockedLoggerClass.mockReturnValue,此时实例早已创建完毕,修改mock返回值不会生效。 - 语法使用错误:
mockReturnValue返回了箭头函数,而new关键字调用类预期返回实例对象,返回的函数不存在log方法自然无法被检测到调用;同时断言toBeCalled需要加括号写成toBeCalled(),否则只是判断属性是否存在,不会执行调用校验。
第二个方案失败原因
- Jest会自动将所有
jest.mock调用提升到模块最顶部执行,优先级高于所有普通变量声明。你定义loggerInstance的代码实际在jest.mock执行之后才运行,mock工厂函数访问loggerInstance时变量还未初始化,因此抛出引用错误。
可行解决方案
方案一:最简适配写法(适合绝大多数场景)
直接在mock工厂函数内定义mock方法,通过mock类的执行记录拿到已经生成的实例的log方法即可:
// 先mock Logger类,返回带mock log方法的实例 jest.mock('./logger', () => { return jest.fn(() => ({ log: jest.fn() })) }) // 按顺序导入依赖和被测试方法 import Logger from './logger' import { myFunction } from './你的业务模块文件名' // 业务代码导入时已经执行过一次new Logger,从mock的执行结果中拿到log的mock函数 const mockLog = (Logger as jest.Mock).mock.results[0].value.log describe('测试myFunction', () => { // 每次用例执行前清空调用记录,避免用例之间互相干扰 beforeEach(() => { mockLog.mockClear() }) it('应该正确调用logger.log并传入参数Hello', () => { myFunction() expect(mockLog).toHaveBeenCalled() expect(mockLog).toHaveBeenCalledWith('Hello') }) })
方案二:支持自定义mock实现的写法
如果需要在不同测试用例中修改log方法的实现、返回值,可以用动态导出的方式避开变量提升问题:
// 提前定义mock方法并导出 export const mockUtils = { mockLog: jest.fn() } // mock工厂函数中通过require动态获取导出的mock方法 jest.mock('./logger', () => { return jest.fn(() => ({ log: require('./当前测试文件的文件名').mockUtils.mockLog })) }) import { myFunction } from './你的业务模块文件名' describe('测试myFunction', () => { beforeEach(() => { mockUtils.mockLog.mockClear() }) it('应该正确调用logger.log', () => { myFunction() expect(mockUtils.mockLog).toHaveBeenCalledWith('Hello') }) it('支持自定义log方法的实现逻辑', () => { mockUtils.mockLog.mockImplementation(() => { // 自定义mock逻辑 }) myFunction() // 其他断言 }) })
内容的提问来源于stack exchange,提问作者Nhu Trinh
相关产品推荐
相关产品推荐

