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

Jest测试跳过S3 getObject调用及异常通过问题排查

问题原因

问题确实出在S3 mock配置和测试用例写法两处错误:

  • 你的业务代码用的是aws-sdk的回调风格调用getObject,调用时第二个参数传入了回调函数,但你写的mock里getObject被设置为jest.fn().mockReturnThis(),调用后只会返回mock实例本身,完全没有处理传入的回调参数,回调永远不会被触发,所以Promise一直处于pending状态,回调内的Checkpoint 2日志自然不会打印。
  • 测试用例中写expect(output).resolves.toEqual('blah')时没有加await,Jest执行完测试函数最后一行就会直接标记测试通过,不会等待pending的Promise变更状态,所以哪怕断言预期值完全错误,也会出现误判通过的情况。
修复方案

你可以根据自己的代码风格选两种修复方式:

方案1:保留现有回调风格业务代码,修正mock逻辑

把mock的getObject改为支持触发传入的回调,同时测试用例中等待Promise执行完成再断言,修正后的测试代码如下:

const s3Handler = require('../s3')
const AWS = require('aws-sdk')

jest.mock('aws-sdk', () => {
  const mockS3 = {
    getObject: jest.fn(),
  }
  return {
    config: {
      update() {
        return {};
      }
    },
    S3: jest.fn(() => mockS3)
  }
})

describe('S3 get object test', () => {
  afterEach(() => {
    jest.clearAllMocks()
  })

  test('should return s3 object content when call success', async () => {
    const mockS3 = new AWS.S3();
    const mockFileContent = 's3file.js'
    // 模拟getObject逻辑:接收参数后立刻执行回调返回成功结果
    mockS3.getObject.mockImplementation((params, callback) => {
      callback(null, mockFileContent)
    })

    const output = await s3Handler.getS3Object('test-bucket', 'test-key');
    expect(output).toEqual(mockFileContent)
    // 校验调用参数是否正确
    expect(mockS3.getObject).toHaveBeenCalledWith(
      { Bucket: 'test-bucket', Key: 'test-key' },
      expect.any(Function)
    )
  })

  test('should throw error when s3 call failed', async () => {
    const mockS3 = new AWS.S3();
    const mockError = new Error('S3 access denied')
    // 模拟调用报错场景
    mockS3.getObject.mockImplementation((params, callback) => {
      callback(mockError, null)
    })

    await expect(s3Handler.getS3Object('test-bucket', 'test-key')).rejects.toThrow(mockError)
  })
})

方案2:改业务代码为aws-sdk原生Promise调用风格

aws-sdk原生支持.promise()方法把回调风格调用转为Promise,不需要自己手动包Promise封装,代码更简洁,适配你最开始写的promise风格mock:
修正后的业务代码:

const AWS = require('aws-sdk');

const s3 = new AWS.S3({ apiVersion: '2012-11-05 ' })

async function getS3Object(bucket, file) {
  const parameters = {
    Bucket: bucket,
    Key: file
  }
  return s3.getObject(parameters).promise()
}
module.exports = {
  getS3Object
}

对应的测试用例记得给Promise断言加await即可:

const s3Handler = require('../s3')
const AWS = require('aws-sdk')

jest.mock('aws-sdk', () => {
  const mockS3 = {
    getObject: jest.fn().mockReturnThis(),
    promise: jest.fn()
  }
  return {
    config: {
      update() {
        return {};
      }
    },
    S3: jest.fn(() => mockS3)
  }
})

describe('S3 get object test', () => {
  test('test', async () => {
    const mockS3 = new AWS.S3();
    const mockResult = 's3file.js'
    mockS3.promise.mockResolvedValueOnce(mockResult);
    const output = await s3Handler.getS3Object('test-bucket', 'test-key');
    expect(output).toEqual(mockResult)
    expect(mockS3.getObject).toHaveBeenCalledWith({ Bucket: 'test-bucket', Key: 'test-key' })
  })
})

注意:所有Jest中涉及异步Promise的断言,要么在expect前加await,要么把Promise直接return出测试函数,否则会出现测试提前退出、断言不生效的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:01:14