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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:25:27