簡體   English   中英

使用假 S3Event 測試我的 AWS Lambda 函數

[英]Testing my AWS Lambda function with a fake S3Event

我正在為從 S3 觸發的 AWS Lambda 實現 Java 8 包,獲取一些文件數據並放入另一個 S3 存儲桶。

這是我當前的Handler程序:

public class Handler implements RequestHandler<S3Event, Void> {
    private static final String TARGET_BUCKET = "some-bucket";

    private AmazonS3Client s3Client = new AmazonS3Client(new DefaultAWSCredentialsProviderChain());
    private Runner runner = new Runner(s3Client, TARGET_BUCKET);

    @Override
    public Void handleRequest(S3Event s3Event, Context context) {
        runner.run(s3Event, context);

        return null;
    }
}

我已將業務邏輯移至我的Runner類,以便我可以正確測試它(遵循AWS Lambda 最佳實踐白皮書)。

但是,我很難了解如何通過假S3Event來測試我的run功能。

我目前的測試是:

@Test
public void putsDataIntoS3() throws IOException {
    runner.run(new ObjectMapper().readValue(loadJsonFromFile("s3-event.json"), S3Event.class), context);

    assertTrue(true);
}

其中loadJsonFromFile使用我傳遞的文件名獲取資源,將其轉換為輸入流,然后轉換為String

但是,這會導致錯誤:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.amazonaws.services.lambda.runtime.events.S3Event]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)

所以我的問題是,如何通過傳遞假的S3Event JSON 來正確測試我的run功能?

這些是我正在使用的與 aws 相關的依賴項:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-core</artifactId>
    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-events</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.11.455</version>
</dependency>

編輯:

我可以像這樣使用S3Event.parseJson函數:我也見過parseJson函數,我可以像這樣使用它:

@Test
public void putsFilteredDataIntoS3() throws IOException {
    runner.run(new S3Event(S3Event.parseJson(loadJsonFromFile("s3-event.json")).getRecords()), context);

    assertTrue(true);
}

但是做這一切是最佳實踐嗎?

您可以使用 Mockito 庫並嘗試模擬此S3Event

從 JSON 創建S3Event的另一個選項:

S3EventNotification notification = S3EventNotification.parseJson(loadJsonFromFile("s3-event.json"));
S3Event event = new S3Event(notification.getRecords());

編輯:第三個選項是將您的aws-lambda-java-events更新到版本2.2.4 ,他們在其中為S3Event添加了默認構造函數,因此您可以像這樣反序列化它:

objectMapper.readValue(loadJsonFromFile("s3-event.json"), S3Event.class)

如果您使用的是 AWS 開發工具包的版本 2,最簡單的方法是使用亞馬遜內部使用的反序列化器:

AWS Lambda Java 運行時序列化

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-serialization</artifactId>
    <version>1.0.0</version>
</dependency>

它的工作原理如下:

PojoSerializer<S3Event> s3EventSerializer = LambdaEventSerializers.serializerFor(S3Event.class, ClassLoader.getSystemClassLoader());
S3Event event = s3EventSerializer.fromJson(inputStream);

有一件重要的事情需要了解(AWS SDK 版本 2 與版本 1)

如果您的 JSON 有問題(不兼容的字段值或 JodaTime 庫不在類路徑中),則序列化程序什么也不說並激活 AWS SDK 1 回退。 最后你會得到這樣的錯誤:

java.lang.ClassNotFoundException: com.amazonaws.services.s3.event.S3EventNotification$S3EventNotificationRecord.

這個消息是錯誤的。 AWS 解串器與版本 2 和版本 1 完美配合。庫本身不依賴於 SDK(無論是 1 還是 2)。 很可能您需要檢查 JSON。

我一直在 S3Event 和 S3NotificationEvent 的兩個包之間遇到問題。

我無法將 json 解析為 com.amazonaws.services.lambda.runtime.events.S3EventNotification 由於

https://github.com/aws/aws-lambda-java-libs/issues/151

閱讀 JSON 后,我得到了com.amazonaws.services.s3.event.S3EventNotification但 FunctionHandler 需要來自 com.amazonaws.services.lambda.runtime.events.S3Event 的com.amazonaws.services.lambda.runtime.events.S3Event

我做不到S3Event(notification.records)

所以我不得不編寫自己的方法來轉換類

    fun test() {
        val fileContent = this::class.java.classLoader.getResource("s3-event.json").readText()
        val s3NotificationEvent = ObjectMapper().registerKotlinModule().readValue(fileContent, S3EventNotification::class.java)
        val s3Event = S3Event(
            s3NotificationEvent.records.map {
                it.toRuntimeS3NotificationRecord()
            }
        )
    )

fun S3EventNotification.S3EventNotificationRecord.toRuntimeS3NotificationRecord(): com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord {
return com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord(
    awsRegion, eventName, eventSource,
    eventTime.toString(), eventVersion,
    com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.RequestParametersEntity(requestParameters.sourceIPAddress),
    com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.ResponseElementsEntity(responseElements.getxAmzId2(), responseElements.getxAmzRequestId()),
    com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3Entity(
        s3.configurationId,
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3BucketEntity(
            s3.bucket.name,
            com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.UserIdentityEntity(s3.bucket.ownerIdentity.principalId),
            s3.bucket.arn
        ),
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3ObjectEntity(s3.`object`.key, s3.`object`.sizeAsLong, s3.`object`.geteTag(), s3.`object`.versionId, s3.`object`.sequencer),
        s3.s3SchemaVersion
    ),
    com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.UserIdentityEntity(userIdentity.principalId)
)

}

您可以使用EventLoader類:

S3Event s3Event = EventLoader.loadS3Event("s3-event.json");

將此依賴項添加到您的項目中:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-tests</artifactId>
    <version>1.0.0</version>
    <scope>test</scope>
</dependency>

有關此主題的更多信息:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM