Node.js+Jest单元测试unzip方法超时问题求助
问题:unzipper解压函数Jest单元测试超时
我实现了一个基于unzipper的小型文件解压函数,功能运行正常,但用Jest做单元测试时出现超时问题。程序基于Node.js 16开发,修改函数会导致功能失效,后续流程依赖解压后的文件,必须解决测试超时问题。
解压函数代码
exports.unzipFile = async (folderPath) => { return new Promise((resolve, reject) => { fs.createReadStream(folderPath) .pipe(unzipper.Extract({ path: tmpPath + path.parse(folderPath).name })) .on('close', () => resolve()) .on('error', (error) => reject(error)) }) }
当前单元测试代码
const { PassThrough } = require('stream') const os = require('os'); const unzipper = require("unzipper") const fs = require("fs") let tmpdir, mockReadStream beforeEach(() => { tmpdir = os.tmpdir() + "/uploadFolder/"; if (!fs.existsSync(tmpdir)){ fs.mkdirSync(tmpdir); } fs.writeFileSync(tmpdir+"tempfile.zip", "file to be used") mockReadStream = new PassThrough() }) afterEach(() => { // Restore mocks jest.clearAllMocks() }) describe('Test helper.js unzip method', () => { test('should be able to unzip file ', async () => { jest.isolateModules(() => { helper = require('helper') }) const result = await helper.unzipFile(tmpdir+"tempfile.zip") console.log(result) }) })
问题原因分析
- 无效Zip文件:测试中写入的
tempfile.zip是普通文本,不是合法Zip包。unzipper处理无效文件时,不会触发close或error事件,导致Promise一直pending,Jest超时。 - 未清理测试资源:
afterEach仅清除Mock,未删除临时文件和目录,可能干扰后续测试。 - 不必要的模块隔离:
jest.isolateModules无配合Mock重置,可能导致模块状态异常。
解决方案
1. 生成合法测试Zip文件
使用archiver生成真实Zip包用于测试:
const archiver = require('archiver'); // 先安装:npm install archiver --save-dev beforeEach(async () => { tmpdir = os.tmpdir() + "/uploadFolder/"; if (!fs.existsSync(tmpdir)){ fs.mkdirSync(tmpdir); } // 生成包含测试文件的Zip包 const output = fs.createWriteStream(tmpdir+"tempfile.zip"); const archive = archiver('zip', { zlib: { level: 9 } }); archive.pipe(output); archive.append('test content', { name: 'test.txt' }); await archive.finalize(); })
2. 完善Promise事件监听
确保所有异常和结束事件都被捕获:
exports.unzipFile = async (folderPath) => { return new Promise((resolve, reject) => { const extractStream = unzipper.Extract({ path: tmpPath + path.parse(folderPath).name }); fs.createReadStream(folderPath) .pipe(extractStream) .on('close', resolve) .on('end', resolve) // 补充end事件监听 .on('error', reject); // 监听extractStream自身的error事件,避免遗漏 extractStream.on('error', reject); }) }
3. 清理测试临时资源
用rimraf递归删除测试目录:
const rimraf = require('rimraf'); // 先安装:npm install rimraf --save-dev afterEach(async () => { jest.clearAllMocks(); // 异步删除临时目录 await new Promise((resolve) => rimraf(tmpdir, resolve)); })
4. 优化测试代码结构
移除不必要的模块隔离,添加断言验证结果:
const helper = require('helper'); // 移到测试文件顶部 describe('Test helper.js unzip method', () => { test('should be able to unzip file', async () => { await helper.unzipFile(tmpdir+"tempfile.zip"); // 断言解压后的文件存在 expect(fs.existsSync(tmpPath + 'tempfile/test.txt')).toBe(true); }, 10000); // 必要时可延长超时时间至10秒 })
内容的提问来源于stack exchange,提问作者Arnoldddd
相关产品推荐
相关产品推荐

