为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
汪汪一只猫 2022-08-15 16:17:50
给定以下用 Go 编写的简单 lambda,它只返回一个表描述...package mainimport (    "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,可以使用如下依赖注入:type deps struct     svc dynamodbiface.DynamoDBAPI    table string}func (d *deps) handler(ctx context.Context, req events.APIGatewayProxyRequest)     (events.APIGatewayProxyResponse, error) {        ...}如何测试使用新的适用于 Go V2 的 AWS 开发工具包编写的 lambda,因为我需要上下文来加载所需的配置?dynamodb.NewFromConfig
查看完整描述

1 回答

?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

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


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

    (events.APIGatewayProxyResponse, error) {

    dynamoWrapper := &RealDynamoWrapper{}

    proxyController := &ProxyController{DynamoWrapper: dynamoWrapper}

    return proxyController.proxy(ctx, req)

这个想法是使处理程序函数变得谦卑,方法是让它将所有复杂性委托给 .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

}

现在,此包装器的真正实现,上面引用的那个将像对 sdk 执行操作一样进行调用。但是,对于我们的测试,我们想要一个模拟实现:RealDynamoWrapper


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...)

}

最后,在测试中,您现在可以模拟发电机调用:


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

}


查看完整回答
反对 回复 2022-08-15
  • 1 回答
  • 0 关注
  • 81 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信