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

使用Sinon打桩同文件导出方法时报B is not a function错误

问题根因

运行测试抛出B is not a function是两个写法错误共同导致的:

  • proxyquire调用格式完全错误:proxyquire 第一个参数必须是被测业务文件(也就是Sol.js)的路径,第二个参数才是依赖替换映射对象。原有写法直接把'F1'写在了参数对象里当键,根本没有完成模块替换的配置,加载的模块导出结构和预期完全不符。
  • 模块导出结构复刻错误:原F1.js的导出逻辑是把module.exports直接赋值为函数A,再在这个函数对象上挂载B属性。原有配置的替换值是一个包含A_stub、B属性的普通对象,既没有让默认导出指向A_stub,也没有把B挂载到默认导出的函数上,Sol.js里解构require('/F1')的B属性时自然拿不到函数。
正确打桩实现

按照下面的逻辑修正即可:

  1. 构造和原模块完全一致的导出结构:以A的桩函数作为整个模块的默认导出,再把B的桩挂载为这个函数的B属性
  2. 修正proxyquire的参数顺序,正确传入被测文件路径和依赖映射
  3. 调整桩的参数签名匹配实际业务调用,避免参数不匹配导致逻辑异常

参考实现代码:

// 定义桩函数
const B_stub = sinon
  .stub()
  .callsFake((param1, param2, callback) => callback(null, result1));

const A_stub = sinon
  .stub()
  // 注意业务中调用A传的第一个参数是{anotherParam, result},桩的参数要对应匹配
  .callsFake(({ anotherParam, result }, cb) => cb(null, result2));

// 复刻原模块的导出结构:默认导出是A函数,函数上挂载B属性
A_stub.B = B_stub;

// 正确调用proxyquire加载被测文件,替换依赖
const testedSol = proxyquire(
  // 第一个参数:填Sol.js在你项目中的实际相对路径
  './path/to/your/Sol.js',
  // 第二个参数:依赖替换映射,键必须和require语句中的路径完全一致
  {
    '/F1': A_stub,
    '@noCallThru': true // 强制使用传入的桩,不加载原F1模块
  }
);

// 后续调用testedSol.somefunction() 执行断言逻辑即可
额外注意事项
  • 桩函数的参数、回调触发逻辑要和原函数保持一致,比如原B是经过callbackify包装的,回调形式是(err, result),B_stub要严格遵守这个形式,否则业务代码拿不到正确返回值
  • Sol.js里分开两次require F1的写法不需要额外处理,Node的模块缓存会保证两次require拿到的都是替换后的桩对象

内容的提问来源于stack exchange,提问作者Madhuri R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 02:18:19