Node.js中testDouble为何无法mock第三方库的导出函数?
问题根因
有两个核心错误导致报错:
- 导入执行顺序问题:ESModule的
import语法存在提升效应,会优先于所有普通代码执行,你当前写的td.replace('skills-lib')虽然位置在import example之前,但实际运行时会先执行import加载业务代码,此时skills-lib还没被mock,业务代码已经拿到了原始的supportsAPL。 - 模块替换规则错误:
td.replace('skills-lib')默认会把整个模块的导出替换为单个测试替身函数,但你的业务代码用的是命名导出import { supportsAPL } from 'skills-lib',相当于你把整个模块变成了函数,业务代码尝试从这个函数上取supportsAPL属性,自然拿不到可执行的函数。
解决方案
方案1:改用CommonJS require保证执行顺序(最简单)
把测试代码里的ESModule import换成require,保证mock操作先于业务模块加载执行,同时正确mock命名导出:
const td = require("testdouble") require("testdouble-jest")(td, jest) // 正确mock命名导出:给skills-lib的导出对象加上supportsAPL替身 const skillsLib = td.replace("skills-lib", { supportsAPL: td.func('supportsAPL') }) // 用require加载业务模块,此时加载的skills-lib已经是mock后的版本 const { example } = require("../lambda/custom/numbers-only") describe("ex", () => { it("ex2", () => { td.when(skillsLib.supportsAPL("a string")).thenReturn(true) const result = example("a string") expect(result).toBe(true) }) })
方案2:保留ESModule写法,使用动态导入
如果你一定要用ESModule的导入语法,可以用动态import()把业务模块的加载放到mock操作之后:
import td from 'testdouble' import testdoubleJest from 'testdouble-jest' testdoubleJest(td, jest) describe("ex", () => { it("ex2", async () => { // 先mock模块 const skillsLib = td.replace("skills-lib", { supportsAPL: td.func('supportsAPL') }) td.when(skillsLib.supportsAPL("a string")).thenReturn(true) // 再动态导入业务模块 const { example } = await import("../lambda/custom/numbers-only") const result = example("a string") expect(result).toBe(true) }) })
额外注意点
你原来的断言用了expect(result).toMatch("true"),toMatch是字符串匹配方法,你的example返回的是布尔值true,直接用expect(result).toBe(true)即可,否则会报类型不匹配的错误。
内容的提问来源于stack exchange,提问作者linker85
相关产品推荐
相关产品推荐

