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

如何用Sinon Stub Node.js(Hapi.js)中require的嵌套子模块?

解决你的Sinon单元测试问题:模块找不到+嵌套依赖Stub

先帮你搞定那个头疼的Cannot find module './library'错误,再教你怎么用Sinon配合工具Stub掉index.js里的library.js,包括它的嵌套第三方依赖。

第一步:修复模块找不到的错误

这个报错大概率是路径或工作目录的问题,你可以先检查这两点:

  • 确认library.js和index.js真的在同一个文件夹下,别打错文件名(注意大小写,Node.js在Linux/macOS下区分文件名大小写)
  • 运行测试命令时的工作目录要正确:比如如果测试文件在test/子文件夹里,别跑到test/目录下执行命令,应该回到项目根目录运行mocha test/testfunc.js这类指令,否则index.js里的./library.js会相对于错误的目录查找文件。

先把这个基础问题解决,再处理Stub的需求。

第二步:用Sinon+Proxyquire Stub嵌套依赖

Sinon本身没法直接替换模块内部已经require进来的依赖,得靠Proxyquire这个工具帮忙拦截模块的依赖加载。它能让我们在加载index.js时,把它依赖的library.js换成Sinon制作的Stub,甚至连library.js里的第三方依赖googlelib也能一起Stub掉。

先安装Proxyquire

先安装这个开发依赖:

npm install proxyquire --save-dev

两种Stub方式,按需选择

假设你的代码结构大概是这样(方便你对应自己的代码):

// index.js
const library = require('./library.js');

exports.runTask = () => {
  return library.processData();
};
// library.js
const googlelib = require('googlelib');

exports.processData = () => {
  return googlelib.fetchData();
};

方式1:连嵌套的googlelib一起Stub

如果需要验证library.js是否调用了googlelib的方法,就用这种方式:

const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('index.js的runTask方法', () => {
  it('应该能Stub library和它依赖的googlelib', () => {
    // 1. 先给googlelib做Stub,模拟它的返回值
    const googlelibStub = {
      fetchData: sinon.stub().returns('模拟的第三方返回数据')
    };

    // 2. 用Proxyquire加载library.js,把它的googlelib换成上面的Stub
    const libraryStub = proxyquire('./library.js', {
      'googlelib': googlelibStub
    });

    // 3. 再加载index.js,把它的library换成我们做好的Stub
    const index = proxyquire('./index.js', {
      './library.js': libraryStub
    });

    // 4. 调用方法并验证
    const result = index.runTask();
    sinon.assert.calledOnce(googlelibStub.fetchData); // 验证googlelib的方法被调用
    console.log(result); // 会输出'模拟的第三方返回数据'
  });
});

方式2:直接Stub library.js的方法

如果你不需要关心library.js内部怎么调用googlelib,只需要模拟library.js的返回结果,那就简单多了:

const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('index.js的runTask方法', () => {
  it('直接Stub library.js就行', () => {
    // 给library做Stub,模拟processData方法的返回
    const libraryStub = {
      processData: sinon.stub().returns('直接模拟的library返回值')
    };

    // 加载index.js,替换它的library依赖
    const index = proxyquire('./index.js', {
      './library.js': libraryStub
    });

    const result = index.runTask();
    sinon.assert.calledOnce(libraryStub.processData); // 验证library的方法被调用
    console.log(result); // 输出'直接模拟的library返回值'
  });
});

为什么不能只用Sinon?

因为Node.js的require会缓存加载过的模块,当你直接require('./index.js')时,它已经把真实的library.js加载并缓存了,Sinon没法替换已经缓存的模块。Proxyquire的作用就是在加载模块的那一刻,拦截它的require调用,把指定的依赖换成我们的Stub,这样就能完全隔离外部依赖,专注测试index.js的核心逻辑了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:19:38