如何使用Jest对存在内部调用关系的两个函数进行Mock测试?
问题排查
原来的测试存在以下错误:
- 第一个测试直接修改导入模块的
componentToHex属性为mock函数无效:rgbToHex内部直接调用同模块的componentToHex,修改导出的引用不会影响模块内部的调用逻辑;同时预期调用次数1错误,rgbToHex处理r、g、b三个参数时会调用3次componentToHex - 第二个测试
jest.spyOn使用错误:第一个参数必须是模块对象,不能传路径字符串;调用未导入的rgbToHex会报错;断言逻辑完全颠倒,rgbToHex入参是三个数字,返回值才是十六进制色值,toHaveBeenCalledWith应该匹配入参而非返回值
正确测试方案
方案1:纯功能测试(优先使用)
工具函数无需mock内部依赖,直接验证输入输出符合预期即可,这是最合理的测试方式:
import * as util from "./utils"; test("componentToHex 单数字转十六进制补零正确", () => { expect(util.componentToHex(15)).toBe("0f"); expect(util.componentToHex(16)).toBe("10"); expect(util.componentToHex(255)).toBe("ff"); }); test("rgbToHex 转换十六进制色值正确", () => { expect(util.rgbToHex(255, 222, 255)).toBe("#ffdeff"); expect(util.rgbToHex(255, 255, 255)).toBe("#ffffff"); expect(util.rgbToHex(0, 0, 0)).toBe("#000000"); });
方案2:需要验证rgbToHex调用componentToHex的逻辑
如果确实需要校验内部调用逻辑,有两种实现方式:
方式一:修改原函数调用逻辑
将原函数内部调用改为通过模块导出对象调用,即可被mock捕获:
// 工具函数修改后代码 export const componentToHex = (c) => { var hex = c.toString(16); return hex.length === 1 ? "0" + hex : hex; }; export const rgbToHex = (r, g, b) => { // 改为通过导出对象调用 return "#" + exports.componentToHex(r) + exports.componentToHex(g) + exports.componentToHex(b); };
对应测试代码:
import * as util from "./utils"; test("rgbToHex 正确调用componentToHex 3次", () => { const spy = jest.spyOn(util, 'componentToHex').mockReturnValue('ff'); const result = util.rgbToHex(255, 222, 255); expect(spy).toHaveBeenCalledTimes(3); expect(spy).toHaveBeenNthCalledWith(1, 255); expect(spy).toHaveBeenNthCalledWith(2, 222); expect(spy).toHaveBeenNthCalledWith(3, 255); expect(result).toBe('#ffffff'); spy.mockRestore(); });
方式二:使用jest.mock全量mock模块
不需要修改原函数代码,直接在测试中mock整个模块即可:
// 放在测试文件最顶部,所有导入语句之前 jest.mock('./utils', () => { const originalModule = jest.requireActual('./utils'); return { ...originalModule, componentToHex: jest.fn(originalModule.componentToHex) }; }); import * as util from "./utils"; test("rgbToHex 正确调用componentToHex 3次", () => { util.rgbToHex(255, 222, 255); expect(util.componentToHex).toHaveBeenCalledTimes(3); expect(util.componentToHex).toHaveBeenNthCalledWith(1, 255); expect(util.componentToHex).toHaveBeenNthCalledWith(2, 222); expect(util.componentToHex).toHaveBeenNthCalledWith(3, 255); });
内容的提问来源于stack exchange,提问作者Moni
相关产品推荐
相关产品推荐

