Node ES Modules环境下如何用Sinon.js stub导出为函数的外部库
解决方案
失效原因
原有写法不生效的核心原因有两个:
- Sinon的stub仅支持替换对象上的属性方法,直接传入函数作为参数时,无法替换其他模块中对原始函数的引用
- Node ES Modules的导入绑定是只读的,直接修改导入的默认导出变量不会生效
方案1:最小修改业务代码(无额外依赖)
仅需在内部业务代码中新增一个可访问的依赖挂载对象,无需修改外部库、无需引入额外测试依赖,非常适合仅少量函数需要测试的场景。
- 修改
mathProblems.js代码:
import sum from 'externalSum' // 新增可导出的依赖挂载对象 export const deps = { sum } export function sumMore1(a) { // 调用挂载对象上的方法,而非直接调用导入的函数 return deps.sum(a, 1); }
- 修改测试文件
spec.js代码:
import sinon from 'sinon' import assert from 'assert' import { sumMore1, deps } from '../mathProblems.js' describe('sumMore1 is working', () => { let sumStub // 每次测试前创建stub beforeEach(() => { sumStub = sinon.stub(deps, 'sum') }) // 每次测试后恢复原始方法,避免用例互相影响 afterEach(() => { sumStub.restore() }) it('sumMore1 test', () => { sumStub.withArgs(1, 1).returns(2) const result = sumMore1(1) assert.strictEqual(result, 2) // 可额外验证调用符合预期 assert.ok(sumStub.calledOnceWith(1, 1)) }); });
方案2:不修改业务代码(轻量依赖方案)
如果完全不想改动业务代码,可以使用专门为ESM设计的轻量mock库esmock,无需模拟CommonJS的require逻辑,配置成本极低。
- 安装依赖:
npm install esmock --save-dev
- 修改测试文件
spec.js代码:
import sinon from 'sinon' import assert from 'assert' import esmock from 'esmock' describe('sumMore1 is working', () => { it('sumMore1 test', async () => { const sumStub = sinon.stub().withArgs(1, 1).returns(2) // 导入业务模块时直接替换外部依赖的导出 const { sumMore1 } = await esmock('../mathProblems.js', { 'externalSum': sumStub }) const result = sumMore1(1) assert.strictEqual(result, 2) }); });
- 运行测试时添加加载器参数即可:
node --loader=esmock node_modules/mocha/bin/mocha spec.js
内容的提问来源于stack exchange,提问作者KevynTD
相关产品推荐
相关产品推荐

