Lambda S3对象下载函数单元测试失败,请求排查
S3下载Lambda函数Jest测试失败:
mockS3Client.send未被调用 问题描述
我编写了一个从S3存储桶下载对象的Lambda处理函数,搭配Jest单元测试,但测试无法通过。报错显示mockS3Client.send方法未被调用,但本地调试时明明执行到了该方法,需要调试帮助。
处理函数代码
import type { GetObjectCommandInput } from "@aws-sdk/client-s3"; import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; import type { S3Event } from "aws-lambda"; async function handler(event: S3Event): Promise<void> { console.log("Received S3 event:", JSON.stringify(event)); for (const record of event.Records) { const params: GetObjectCommandInput = { Bucket: record.s3.bucket.name, Key: record.s3.object.key, }; const getObjectCommand = new GetObjectCommand(params); const s3Data = await s3Client.send(getObjectCommand); console.log(s3Data); } }
单元测试代码
import { handler } from "~/resources/mons"; import { S3Event } from "aws-lambda"; const mockEvent: S3Event = { Records: [ { eventVersion: "2.1", eventSource: "aws:s3", awsRegion: "us-east-1", eventTime: "2024-02-26T16:35:36.549Z", eventName: "ObjectCreated:Put", userIdentity: { principalId: "AWS:AROAW3MD7IRJM6QRM6RCR:abgaura-Isengard", }, requestParameters: { sourceIPAddress: "72.21.198.71", }, responseElements: { "x-amz-request-id": "0Q0FHDKGYS01M9G0", "x-amz-id-2": "D6DaPnYNIw1F3shV+GZY4XdKhxt0hsWlrZf7JC1PIOm3IfrgQsG6Lekf4m1nqIM1RPiTDgUtM2iyzA2o2DwotZTtSYtZEt1H", }, s3: { s3SchemaVersion: "1.0", configurationId: "NTYzOWU1NjQtMjY3Zi00OGNiLTk4ZWItNDljYjY1MjJjMTJl", bucket: { name: "santosblueringwebapp-dev-471112565842-us-east-1", ownerIdentity: { principalId: "A3UY9USU3LZ6NZ", }, arn: "arn:aws:s3:::santosblueringwebapp-dev-471112565842-us-east-1", }, object: { key: "dist/index.sece.html", size: 1064, eTag: "cf1a8087d548591d0328589e075a360d", versionId: "8UCtubZ8etB_x6v1fdzJKLNffD8gsC0G", sequencer: "0065DCBDD88107E020", }, }, }, ], }; describe("Handler", () => { const mockS3Client = { send: jest.fn().mockResolvedValue({ /* Mocked response */ }), }; jest.mock("@aws-sdk/client-s3", () => ({ S3Client: jest.fn(() => mockS3Client), GetObjectCommand: jest.fn(), })); beforeEach(() => { jest.clearAllMocks(); }); test("retrieves objects from S3 and transforms them to strings", async () => { await handler(mockEvent); expect(mockS3Client.send).toHaveBeenCalled(); }); });
测试报错信息
expect(jest.fn()).toHaveBeenCalled() Expected number of calls: >= 1 Received number of calls: 0 60 | test("retrieves objects from S3 and transforms them to strings", async () => { 61 | await handler(mockEvent); > 62 | expect(mockS3Client.send).toHaveBeenCalled();
问题根源与修复方案
1. 处理函数未正确初始化S3Client实例
处理函数中直接使用了s3Client.send,但未声明或初始化该变量。本地调试时可能全局环境存在该实例,但测试环境中Jest模拟的S3Client未被正确赋值,导致调用的不是你定义的mock实例。
修复:在处理函数中显式创建S3Client实例:
// 显式创建S3Client实例 const s3Client = new S3Client({}); async function handler(event: S3Event): Promise<void> { // ... 原有代码逻辑 }
2. Jest模拟的作用域与时机问题
jest.mock会被提升到模块顶部执行,此时describe块内的mockS3Client还未定义,导致模拟的S3Client构造函数返回undefined,实际调用的不是你期望的mock实例。
修复方案A(推荐):在mock工厂函数内部定义mock实例
describe("Handler", () => { let mockSend: jest.Mock; // 在mock工厂内创建并暴露mock方法 jest.mock("@aws-sdk/client-s3", () => { mockSend = jest.fn().mockResolvedValue({}); return { S3Client: jest.fn(() => ({ send: mockSend })), GetObjectCommand: jest.fn(), }; }); beforeEach(() => { jest.clearAllMocks(); }); test("retrieves objects from S3 and transforms them to strings", async () => { await handler(mockEvent); // 验证mockSend被调用 expect(mockSend).toHaveBeenCalled(); // 可额外验证GetObjectCommand的调用参数 expect(GetObjectCommand).toHaveBeenCalledWith(expect.objectContaining({ Bucket: mockEvent.Records[0].s3.bucket.name, Key: mockEvent.Records[0].s3.object.key })); }); });
3. 补充验证逻辑
测试中可增加对GetObjectCommand的调用验证,确保参数传递正确,进一步定位问题。
内容的提问来源于stack exchange,提问作者Let us see.
相关产品推荐
相关产品推荐

