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

Jest运行模拟AWS S3文件读取测试超时,如何正确mock createReadStream?

问题根因

你当前对S3读取流的Mock仅定义了空的on函数,没有主动触发data、end事件,导致getBufferFromS3内的回调永远不会执行,包裹的Promise长期处于pending状态,最终触发超时。

解决方案

提供两种可选方案,你可以根据场景选择:

方案1:修复S3流的Mock逻辑

不需要修改业务代码,直接调整测试里的S3 Mock配置,让流主动触发对应事件:

// 模拟真实的xlsx文件buffer
const mockXlsxBuffer = Buffer.from('fake xlsx content');
const mockgetObject = {
    createReadStream: jest.fn(() => {
        return {
            on: jest.fn((eventName, callback) => {
                // 触发data事件返回模拟内容
                if (eventName === 'data') {
                    callback(mockXlsxBuffer);
                }
                // 触发end事件标记读取完成
                if (eventName === 'end') {
                    callback();
                }
                // 如需测试错误场景,可加eventName === 'error'分支传入错误对象
                return this;
            })
        }
    })
}

方案2:直接Mock getBufferFromS3Promise(更简洁)

如果允许小幅度调整业务代码,把内部的getBufferFromS3Promise抽成类的公有方法,就可以直接Mock跳过流处理逻辑,减少Mock复杂度:

第一步:调整业务代码handler.ts

将createWorkbookFromS3内部的getBufferFromS3Promise抽为Service类的公有方法:

class Service {
    client: any;
    workbook: any = "";

    constructor(client) {
        this.workbook = "";
        this.client = client;
    }

    // 抽出来的可Mock方法
    async getBufferFromS3Promise(fileLocation: string) {
        const params = {
          Bucket: "bucket",
          Key: fileLocation,
        };
        function getBufferFromS3(callback) {
          const buffers = [];
          const s3 = new AWS.S3();
          const stream = s3.getObject(params).createReadStream();
          stream.on("data", (data) => buffers.push(data));
          stream.on("end", () => callback(null, Buffer.concat(buffers)));
          stream.on("error", (error) => callback(error));
        }
        return new Promise((resolve, reject) => {
            getBufferFromS3((error, s3buffer) => {
              if (error) return reject(error);
              return resolve(s3buffer);
            });
        });
    }

    async createWorkbookFromS3(filePath: string, id: string) {
        const fileLocation = id + filePath;
        try {
          const buffer = await this.getBufferFromS3Promise(fileLocation);
          this.workbook = XLSX.read(buffer);
        } catch (e) {
          this.client.release()
          console.error(e);
          throw new Error("Unable to read the xlsx from S3");
        }
      }
}

第二步:测试代码直接Mock该方法

it('should execute decoder', async () => {
    const id = 'id';
    const filePath = 'filePath'
    const service = new decoder.Service(client);
    // 直接Mock返回模拟buffer,不需要处理S3流逻辑
    jest.spyOn(service, 'getBufferFromS3Promise').mockResolvedValue(Buffer.from('fake xlsx content'));
    await service.createWorkbookFromS3(filePath, id)
    // 剩余测试逻辑
})
其他需要修复的测试问题

就算流的问题修复,你现有测试代码还有以下问题会导致执行失败:

  • 测试传入的event路径是/decoder/draft,但业务代码里匹配的路径是/vsiDecoder/draft,路径不匹配会直接返回400
  • 业务代码里dbCredentials是硬编码的普通对象,没有SecretString属性,调用JSON.parse(dbCredentials['SecretString'])会报错,需要调整业务代码的dbCredentials定义,或者Mock对应的取值逻辑
  • 调用createWorkbookFromS3时参数传反了,方法定义第一个参数是filePath,第二个是id,你当前传的是(id, filePath)
  • 业务返回的是原生对象,你测试里期望的是JSON字符串,不需要序列化,直接对比对象即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:45:04