gpt4 book ai didi

unit-testing - 如何对使用适用于 Go V2 的 AWS 开发工具包实现的 Lambda 进行单元测试

转载 作者:行者123 更新时间:2023-12-05 06:03:54 24 4
gpt4 key购买 nike

给定以下用 Go 编写的简单 lambda,它只返回一个表描述...

package main

import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"go.uber.org/zap"
)

var (
dynamoDBTableName = aws.String(os.Getenv(EnvDynamoDBTableName))

logger = func() *zap.Logger {
l, err := zap.NewProduction()
if err != nil {
log.Printf("failed to create zap logger: %v", err)
}
return l
}()
)

func handler(ctx context.Context, req events.APIGatewayProxyRequest)
(events.APIGatewayProxyResponse, error) {

defer logger.Sync()

resp := events.APIGatewayProxyResponse{}

cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
logger.Error("failed to load AWS config", zap.Error(err))
return resp, fmt.Errorf("failed to load AWS config: %w", err)
}

svc := dynamodb.NewFromConfig(cfg)

// fake logic
t, err := svc.DescribeTable(ctx, &dynamodb.DescribeTableInput{TableName: dynamoDBTableName})
if err != nil {
logger.Error("failed to describe table", zap.String("table-name", *dynamoDBTableName), zap.Error(err))
}
var sb strings.Builder
enc := json.NewEncoder(&sb)
err = enc.Encode(t.Table)
if err != nil {
logger.Error("failed to JSON encode response", zap.Error(err))
}
resp.Body = sb.String()
resp.StatusCode = http.StatusOK

return resp, nil
}

func main() {
lambda.Start(handler)
}

...我如何在本地对其进行单元测试?使用旧的 SDK 可以像这样使用依赖注入(inject):

type deps struct 
svc dynamodbiface.DynamoDBAPI
table string
}

func (d *deps) handler(ctx context.Context, req events.APIGatewayProxyRequest)
(events.APIGatewayProxyResponse, error) {

...
}

func main() {
s := session.Must(session.NewSession())
d := deps {
svc: dynamodb.New(s),
table: dynamoDBTableName,
}

lambda.Start(d.handler)
}

鉴于我需要上下文来加载 dynamodb.NewFromConfig 所需的配置,我该如何测试使用适用于 Go V2 的新 AWS SDK 编写的 lambda?

最佳答案

首先让你的处理程序成为一个不起眼的对象,这样我们就可以“跳过”测试它:

func handler(ctx context.Context, req events.APIGatewayProxyRequest) 
(events.APIGatewayProxyResponse, error) {
dynamoWrapper := &RealDynamoWrapper{}
proxyController := &ProxyController{DynamoWrapper: dynamoWrapper}
return proxyController.proxy(ctx, req)

这个想法是通过将所有复杂性委托(delegate)给 proxyController 来使处理程序功能变得简单。

现在,让我们考虑要测试的 ProxyController,我们需要先定义它:

type ProxyController struct {
dynamoWrapper DynamoWrapper
}

func(controller *ProxyController) Proxy(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// this is where your implementation lives that you need to mock stuff for

// We are mocking this line from your question
svc := controller.dynamoWrapper.NewFromConfig(...)

// do other stuff and then return something
return events.APIGatewayProxyResponse{}, nil
}

你可以看到我将依赖于 dynamo 的包装版本,它看起来像这样:

type DynamoWrapper interface {
NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client
}

现在这个包装器的真正实现,上面提到的 RealDynamoWrapper 将像您对 sdk 一样进行调用。不过,对于我们的测试,我们需要一个模拟实现:

type mockDynamoWrapper struct {
NewFromConfigFunc func(aws.Config, ...func(*Options)) *Client
}

func(dynamoWrapper *mockDynamoWrapper) NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
return dynamoWrapper.NewFromConfigFunc(cfg, optFns...)
}

最后,在您的测试中,您现在可以模拟 dynamo 调用:

func TestProxyController(t *testing.T) {
// given
dynamoWrapper := &mockDynamoWrapper{}
proxyController := &ProxyController{DynamoWrapper: mockDynamoWrapper}
request := events.APIGatewayProxyRequest{}
dynamoWrapper.NewFromConfigFunc = func(aws.Config, ...func(*Options)) *Client {
// setup your mock function to do whatever you want
}

// when
proxyController.proxy(context.Background, request)

// then do your asserts
}

关于unit-testing - 如何对使用适用于 Go V2 的 AWS 开发工具包实现的 Lambda 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66534288/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com