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

Stub第三方库函数后仍抛出ENOENT错误,如何解决?

问题概述

测试自定义函数时,无法正确Stub其内部调用的第三方库函数。

我的代码

myCustomFunctions.js中的代码:

function myFunc(resource) {
  const thirdPartyFunc = require('third-party-lib')

  try {
      let thirdPartyFuncOutput = thirdPartyFunc(resource.path);
      return;
  } catch (e) {
      vscode.window.showErrorMessage(`Something went wrong: ${e}`);
      return;
  }
}

我的测试代码

测试套件代码:

const myCustomFunctions = require('../../myCustomFunctions.js');

suite('testing myCustomFunctions.js', function () {
  setup(function () {
    sandbox = sinon.createSandbox();
    mockedInput = {
      path: 'something',
      options: {}
    };
  });

  teardown(function () {
    sandbox.restore();
  });

  test('Should generate expected output for valid resource', async function () {
    const expectedOutput = 'Hi Mom';
    const thirdPartyFuncStub = sandbox.stub().returns(expectedOutput);

    // 尝试替换第三方方法的响应
    myCustomFunctions.thirdPartyFunc = thirdPartyFuncStub

    await myCustomFunctions.myFunc(mockedInput);

    // 断言逻辑
  });
})

问题现象

测试执行到let thirdPartyFuncOutput = thirdPartyFunc(resource.path);时,未返回Mock值,反而抛出错误:

Error: ENOENT: no such file or directory, lstat 'something'

明明创建了Stub,原函数却仍在处理真实输入,Stub未生效的原因是什么?

环境信息

  • node v18.16.1
  • mocha v10.2.0
  • sinon v15.2.0

解决方案

核心原因

你在myFunc内部调用require('third-party-lib'),意味着每次执行myFunc都会重新加载第三方库模块,而不是复用模块缓存或你在测试中替换的引用。测试中给myCustomFunctions.thirdPartyFunc赋值的Stub,和函数内部的thirdPartyFunc是完全独立的两个引用,Stub自然无法生效。

修复步骤

方法1:将第三方库的require移到模块顶部,导出依赖(推荐)

修改myCustomFunctions.js,把require移到模块外层,模块加载时只会执行一次require,测试时可直接Stub模块导出的引用:

// 移到模块顶部,仅加载一次
const thirdPartyFunc = require('third-party-lib');

function myFunc(resource) {
  try {
      let thirdPartyFuncOutput = thirdPartyFunc(resource.path);
      return;
  } catch (e) {
      vscode.window.showErrorMessage(`Something went wrong: ${e}`);
      return;
  }
}

// 导出函数和依赖,方便测试时Stub
module.exports = {
  myFunc,
  thirdPartyFunc
};

测试代码中,直接Stub模块导出的thirdPartyFunc:

const myCustomFunctions = require('../../myCustomFunctions.js');

suite('testing myCustomFunctions.js', function () {
  // ... 其他代码不变

  test('Should generate expected output for valid resource', async function () {
    const expectedOutput = 'Hi Mom';
    // 直接Stub模块导出的thirdPartyFunc
    sandbox.stub(myCustomFunctions, 'thirdPartyFunc').returns(expectedOutput);

    await myCustomFunctions.myFunc(mockedInput);

    // 示例断言:验证第三方函数被正确调用
    sinon.assert.calledWith(myCustomFunctions.thirdPartyFunc, 'something');
  });
})

方法2:操作Node.js模块缓存Stub(侵入性强,不推荐)

如果不想修改原代码结构,可以通过Node.js的模块缓存机制Stub:

test('Should generate expected output for valid resource', async function () {
  const expectedOutput = 'Hi Mom';
  // 获取第三方模块的缓存引用
  const thirdPartyLib = require('third-party-lib');
  // 根据模块导出类型Stub(默认导出用default,命名导出用对应属性名)
  sandbox.stub(thirdPartyLib, 'default').returns(expectedOutput);

  await myCustomFunctions.myFunc(mockedInput);

  // 断言逻辑
});

这种方法依赖Node.js内部机制,代码可读性差,不适合长期维护的项目。

额外注意点

  • 原代码中thirdPartyFunc(path)的path未定义,需修正为resource.path,否则会触发path is not defined错误。
  • 测试代码中模块引入的变量名要统一,原代码里const myFunc = require(...)和后续myCustomFunctions.myFunc的变量名不一致,需修正。

内容的提问来源于stack exchange,提问作者null-point-exceptional

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 02:55:31