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

如何在Sinon中stub通过解构require导入的函数且不修改原文件引入方式

问题根因

CommonJS的模块加载是运行时执行的,fileB 中通过解构 const { doSomething } = require('./fileA') 导入时,会直接将原doSomething函数的引用复制到fileB的作用域中。你原测试代码中先加载了fileB再stub fileA上的方法,只是修改了fileA导出对象的属性指向,并没有修改fileB中已经保存的原函数引用,因此stub不生效。

解决方案1:调整模块加载顺序(无需额外依赖)

只要在加载fileB之前就完成对fileA对应方法的stub,此时fileB解构拿到的就是stub后的函数引用:

const sinon = require('sinon');
const { expect } = require('chai');
const fileA = require('./fileA');

// 先stub fileA的方法,再加载fileB
const fileAStub = sinon.stub(fileA, 'doSomething').returns(15);
const fileB = require('./fileB');

describe('Test File B', function(){
  afterEach(function() {
    // 测试结束恢复原方法,避免影响其他用例
    fileAStub.restore();
    // 清除模块缓存,避免其他测试加载到缓存的fileB
    delete require.cache[require.resolve('./fileB')];
  })

  it('stub生效示例', function() {
    expect(fileB.doAnotherThing()).to.equal(25);
  })
})

解决方案2:使用proxyquire(更灵活,无全局污染)

proxyquire是专门用于替换NodeJS模块依赖的工具,可以在加载目标模块时临时替换它的依赖,不会修改全局模块缓存,更适合多测试用例的场景:

const sinon = require('sinon');
const { expect } = require('chai');
const proxyquire = require('proxyquire');

describe('Test File B', function(){
  it('stub生效示例', function() {
    // 构造替换用的stub
    const fileAStub = sinon.stub().returns(15);
    // 加载fileB时,将它依赖的./fileA替换为我们自定义的对象
    const fileB = proxyquire('./fileB', {
      './fileA': {
        doSomething: fileAStub
      }
    });

    expect(fileB.doAnotherThing()).to.equal(25);
  })
})

注意事项

  • 方案1需要手动处理模块缓存清除和stub恢复,否则会造成测试用例之间的相互影响
  • 方案2不需要额外处理缓存,每次调用proxyquire加载的模块都是独立实例,更推荐在复杂测试场景下使用

内容的提问来源于stack exchange,提问作者Zongwei Kay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:54:04