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

Node.js中testDouble为何无法mock第三方库的导出函数?

问题根因

有两个核心错误导致报错:

  1. 导入执行顺序问题:ESModule的import语法存在提升效应,会优先于所有普通代码执行,你当前写的td.replace('skills-lib')虽然位置在import example之前,但实际运行时会先执行import加载业务代码,此时skills-lib还没被mock,业务代码已经拿到了原始的supportsAPL。
  2. 模块替换规则错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 08:15:03