如何使用Jest对file.ts进行单元测试并Mock createWriteStream
使用Jest测试文件上传保存功能(TypeScript)
一、Mock关键依赖
要测试saveUpload函数,需要Mock三个核心依赖:uuid.v4、fs.createWriteStream,以及传入的file对象的createReadStream方法,确保测试不依赖真实文件系统或随机生成的ID。
1. Mock uuid.v4
uuid.v4每次生成唯一ID,测试时固定返回值,让生成的文件路径可预测:
jest.mock('uuid', () => ({ v4: jest.fn().mockReturnValue('test-fixed-uuid') }));
2. Mock fs.createWriteStream
模拟createWriteStream返回带pipe方法的流,同时实现on方法触发finish事件(让原代码的await能正常完成)。如果要模拟错误场景,可触发error事件:
// 正常场景的Mock const mockCreateWriteStream = jest.fn(() => ({ pipe: jest.fn().mockReturnThis(), on: jest.fn((event, callback) => { if (event === 'finish') callback(); }) })); jest.mock('fs', () => ({ createWriteStream: mockCreateWriteStream }));
二、编写测试用例
创建file.test.ts文件,覆盖成功保存和错误抛出两种场景:
1. 测试成功保存文件
import { saveUpload } from './file'; import { join } from 'path'; import { v4 as uuidV4 } from 'uuid'; import { createWriteStream } from 'fs'; // 提前Mock依赖 jest.mock('uuid', () => ({ v4: jest.fn().mockReturnValue('test-fixed-uuid') })); const mockCreateWriteStream = jest.fn(() => ({ pipe: jest.fn().mockReturnThis(), on: jest.fn((event, cb) => event === 'finish' && cb()) })); jest.mock('fs', () => ({ createWriteStream: mockCreateWriteStream })); describe('saveUpload', () => { it('成功保存文件并返回正确路径', async () => { // 模拟传入的file对象 const mockFile = { filename: 'demo.txt', createReadStream: jest.fn().mockReturnValue({ pipe: jest.fn().mockReturnThis(), on: jest.fn((event, cb) => event === 'finish' && cb()) }) }; const result = await saveUpload(mockFile); // 验证生成的路径是否符合预期 const expectedPath = join(__dirname, '../../src/uploads/test-fixed-uuid-demo.txt'); expect(result).toBe(expectedPath); // 验证依赖调用是否正确 expect(createWriteStream).toHaveBeenCalledWith(expectedPath); expect(mockFile.createReadStream).toHaveBeenCalled(); expect(mockFile.createReadStream().pipe).toHaveBeenCalled(); }); });
2. 测试保存失败时抛出错误
it('保存出错时抛出对应错误', async () => { const testError = new Error('文件写入失败'); // 模拟流触发错误事件 const mockFile = { filename: 'demo.txt', createReadStream: jest.fn().mockReturnValue({ pipe: jest.fn().mockImplementation(() => ({ on: jest.fn((event, cb) => { if (event === 'error') cb(testError); }) })) }) }; await expect(saveUpload(mockFile)).rejects.toThrow(testError); });
三、核心注意点
- 原代码的
await依赖流的finish事件,所以Mock的流必须触发该事件,否则测试会超时。 - 所有外部依赖都要Mock,避免测试依赖真实环境,保证测试的稳定性和可重复执行性。
- 必须覆盖成功和异常场景,确保函数的正常逻辑和错误处理都能被验证。
内容的提问来源于stack exchange,提问作者Aya Hashem
相关产品推荐
相关产品推荐

