s3客户端测试的疑惑

问题描述 投票:0回答:1

我有以下代码和单元测试。它是一个简单的 lambda 处理函数,用于从 S3 存储桶下载对象。我无法成功地为其编写单元测试。需要调试帮助。

处理程序代码

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();

当我在本地使用调试器时,我看到它命中了发送,但测试无法识别。我错过了什么??

amazon-web-services amazon-s3 jestjs babel-jest
1个回答
0
投票

我调试了测试代码,发现

GetObjectCommand
S3Client
没有被模拟。要模拟模块,似乎必须在测试模块的根部调用
jest.mock()

https://github.com/kentcdodds/how-jest-mocking-works

事实证明,如果您在模块的根目录中调用 jest.mock,则模拟将在任何 require 语句解析/运行之前发生。

为了通过测试,我做了如下调整(寻找 4 个感叹号)。

处理程序代码

const s3Client = new S3Client();  // !!!! Added this line
const s3Data = await s3Client.send(getObjectCommand);

单元测试

import { handler } from "~/resources/mons";
import { S3Event } from "aws-lambda";

// !!!!
// Moved module mocking to the root of the test module
// !!!!
const mockS3Client = {
    send: jest.fn().mockResolvedValue({
        /* Mocked response */
    }),
};
jest.mock("@aws-sdk/client-s3", () => ({
    S3Client: jest.fn(() => mockS3Client),
    GetObjectCommand: jest.fn(),
}));

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", () => {
    beforeEach(() => {
        jest.clearAllMocks();
    });

    test("retrieves objects from S3 and transforms them to strings", async () => {
        await handler(mockEvent);
        expect(mockS3Client.send).toHaveBeenCalled();
    });
});  // !!!! Added ");"

© www.soinside.com 2019 - 2024. All rights reserved.