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

如何在sinon中mock文件I/O 解决unzip函数单元测试mkdir EEXIST报错

报错原因

你没有 mock fs.mkdir 相关逻辑,测试时调用了真实的系统 mkdir 操作,传入的目标路径已存在所以抛出 EEXIST 错误,同时你的测试代码还有多处 mock 不匹配的问题,按下面方案修改即可:

修改后的测试代码

ava.beforeEach(() => {
  // mock mkdir 方法,直接 resolve 避免真实操作文件系统
  const mockMkdir = sinon.stub().resolves();
  sinon.stub(mockFs, 'mkdir', mockMkdir);

  // mock createReadStream 及流事件逻辑
  sinon.stub(mockFs, 'createReadStream').returns({
    pipe: sinon.stub().returns({
      on: sinon.stub().callsFake((event, callback) => {
        // 绑定 close 事件时主动触发回调,让 unZip 函数的 promise 正常 resolve
        if (event === 'close') callback();
        return this;
      })
    }),
  });

  t.context.mockMkdir = mockMkdir;
});

ava.serial('unZip test', async (t) => {
  const { mockMkdir } = t.context;
  const unzip = proxyquire('../../../src/helpers/file/unZip', {
    fs: mockFs,
    // 补全 util.promisify 的 mock 逻辑
    util: {
      promisify: sinon.stub().callsFake(fn => fn === mockFs.mkdir ? mockMkdir : fn)
    },
    // 修正 unzipper.Extract 的返回值,符合 pipe 方法的入参要求
    unzipper: { Extract: () => ({}) },
  });

  const testZipPath = 'fakeFileContent';
  const testDestDir = 'fakeTestDir';
  const result = await unzip(testZipPath, testDestDir);

  // 原函数 resolve 的是目标目录路径,修正断言
  t.is(result, testDestDir);
  // 可选:验证 mkdir 被正确调用
  t.true(mockMkdir.calledOnceWith(testDestDir));
});

可选业务代码优化

如果你的业务场景允许目标目录已存在,可以直接修改原 unZip 函数的 mkdir 调用,增加 recursive: true 参数,原生支持目录已存在时不报错,逻辑更健壮:

await util.promisify(fs.mkdir)(destDir, { recursive: true });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 20:24:01