如何在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
相关产品推荐
相关产品推荐

