如何用Jest正确mock S3的createPresignedPost方法
问题原因
- 参数多出匿名函数:
AWS.S3.createPresignedPost本身接收两个入参,第一个是配置对象,第二个是执行完成后的回调函数。原测试断言只校验了第一个配置参数,没有将第二个回调参数纳入预期,因此触发参数不匹配报错。 - 无法正常await调用:
- 原测试用例注释掉了
async修饰符和await关键字 - 原mock实现不符合接口的实际调用逻辑:
createPresignedPost是回调风格API,本身不返回带promise()方法的对象,需要让mock主动触发传入的回调,才能让业务函数外层包裹的Promise正常决议,await才不会卡住。
- 原测试用例注释掉了
修复后的测试代码
const createPresignedPost = require('./你的业务文件路径'); const mockedCreatePresignedPost = jest.fn((params, callback) => { // 模拟调用成功,触发回调返回模拟数据 callback(null, { url: 'https://mock-s3-url.com', fields: { mockKey: 'mockValue' } }); }); jest.mock('aws-sdk', () => { return { S3: jest.fn(() => ({ createPresignedPost: mockedCreatePresignedPost })), config: { update: jest.fn() } }; }); // 加async修饰符 it('has to mock S3#createPresignedPost', async () => { process.env.AWS_BUCKET_NAME = 'test1'; const params = { key: 'test2', contentType: 'application/json' }; const s3params = { Bucket: 'test1', Conditions: [['content-length-range', 100, 10000000]], Expires: 60, Fields: { 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'max-age=31536000', 'Content-Type': params['contentType'], key: params['key'] } }; // 加await调用 const result = await createPresignedPost(params); // 断言时加入第二个回调参数的匹配,用expect.any(Function)匹配任意函数 expect(mockedCreatePresignedPost).toHaveBeenCalledWith(s3params, expect.any(Function)); // 可选:断言返回结果符合预期,提升覆盖率 expect(result).toEqual({ url: 'https://mock-s3-url.com', fields: { mockKey: 'mockValue' } }); });
核心修改说明
- 调整
mockedCreatePresignedPost的实现:接收到传入的回调函数后主动触发,模拟接口调用成功的逻辑,保证外层Promise可以正常决议 - 给测试用例加
async修饰符,调用业务函数时加await,解决异步调用问题 - 断言参数时加入
expect.any(Function)匹配第二个回调参数,消除参数不匹配报错 - 额外增加返回结果的断言,可以覆盖业务函数中Promise resolve的分支,进一步提升测试覆盖率,满足CI阈值要求
可选:覆盖错误分支(进一步提升覆盖率)
如果需要覆盖接口报错的reject分支,可以新增如下测试用例:
it('handles S3 createPresignedPost error', async () => { const mockError = new Error('S3 service error'); mockedCreatePresignedPost.mockImplementationOnce((params, callback) => { callback(mockError); }); await expect(createPresignedPost({ key: 'test', contentType: 'text/plain' })).rejects.toThrow(mockError); });
内容的提问来源于stack exchange,提问作者Igor Shmukler
相关产品推荐
相关产品推荐

