gpt4 book ai didi

amazon-web-services - AWS SDK Go Lambda 单元测试

转载 作者:行者123 更新时间:2023-12-03 10:09:15 24 4
gpt4 key购买 nike

我正在尝试第一次全神贯注地编写一些单元测试,并且我正在 golang 中为使用 aws lambda 的辅助项目做这件事。
下面是两个文件。main.go接受一个包含电子邮件地址的事件,并在认知用户池中创建用户。main_test.go应该模拟 createUser main.go中的函数,但是当我尝试运行测试时出现错误。
我刚刚从 instantiating the client globally 切换了我的代码在观看 this youtube video 之后在 aws sdk 接口(interface)上使用指针接收器方法.
main.go

package main

import (
"fmt"
"log"
"os"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
cidp "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
cidpif "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
lib "github.com/sean/repo/lib"
)

type createUserEvent struct {
EmailAddress string `json:"email_address"`
}

type awsService struct {
cidpif.CognitoIdentityProviderAPI
}

func (c *awsService) createUser(e createUserEvent) error {
input := &cidp.AdminCreateUserInput{
UserPoolId: aws.String(os.Getenv("USER_POOL_ID")),
Username: aws.String(e.EmailAddress),
DesiredDeliveryMediums: []*string{aws.String("EMAIL")},
ForceAliasCreation: aws.Bool(true),
UserAttributes: []*cidp.AttributeType{
{
Name: aws.String("email"),
Value: aws.String(e.EmailAddress),
},
},
}
_, err := c.AdminCreateUser(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case cidp.ErrCodeResourceNotFoundException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeResourceNotFoundException, aerr.Error())
case cidp.ErrCodeInvalidParameterException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidParameterException, aerr.Error())
case cidp.ErrCodeUserNotFoundException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUserNotFoundException, aerr.Error())
case cidp.ErrCodeUsernameExistsException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUsernameExistsException, aerr.Error())
case cidp.ErrCodeInvalidPasswordException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidPasswordException, aerr.Error())
case cidp.ErrCodeCodeDeliveryFailureException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeCodeDeliveryFailureException, aerr.Error())
case cidp.ErrCodeUnexpectedLambdaException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUnexpectedLambdaException, aerr.Error())
case cidp.ErrCodeUserLambdaValidationException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUserLambdaValidationException, aerr.Error())
case cidp.ErrCodeInvalidLambdaResponseException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidLambdaResponseException, aerr.Error())
case cidp.ErrCodePreconditionNotMetException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodePreconditionNotMetException, aerr.Error())
case cidp.ErrCodeInvalidSmsRoleAccessPolicyException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidSmsRoleAccessPolicyException, aerr.Error())
case cidp.ErrCodeInvalidSmsRoleTrustRelationshipException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInvalidSmsRoleTrustRelationshipException, aerr.Error())
case cidp.ErrCodeTooManyRequestsException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeTooManyRequestsException, aerr.Error())
case cidp.ErrCodeNotAuthorizedException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeNotAuthorizedException, aerr.Error())
case cidp.ErrCodeUnsupportedUserStateException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeUnsupportedUserStateException, aerr.Error())
case cidp.ErrCodeInternalErrorException:
log.Printf("[ERROR] %v, %v", cidp.ErrCodeInternalErrorException, aerr.Error())
default:
log.Printf("[ERROR] %v", err.Error())
}
} else {
log.Printf("[ERROR] %v", err.Error())
}
return err
}
log.Printf("[INFO] Created new user %v successfully", e.EmailAddress)
return nil
}

func (c *awsService) handler(e createUserEvent) (events.APIGatewayProxyResponse, error) {
headers := map[string]string{"Content-Type": "application/json"}

err := c.createUser(e)
if err != nil {
resp := lib.GenerateResponseBody(fmt.Sprintf("Error creating user %v", e.EmailAddress), 404, err, headers)
return resp, nil
}

resp := lib.GenerateResponseBody(fmt.Sprintf("Created new user %v", e.EmailAddress), 200, nil, headers)
return resp, nil
}

func main() {
c := awsService{cidp.New(session.New())}

lambda.Start(c.handler)
}
main_test.go
package main

import (
"os"
"testing"

cidp "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
cidpif "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
)

type mockCreateUser struct {
cidpif.CognitoIdentityProviderAPI
Response cidp.AdminCreateUserOutput
}

func (d mockCreateUser) CreateUser(e createUserEvent) error {
return nil
}

func TestCreateUser(t *testing.T) {
t.Run("Successfully create user", func(t *testing.T) {
m := mockCreateUser{Response: cidp.AdminCreateUserOutput{}}
c := awsService{m}

err := os.Setenv("USER_POOL_ID", "ap-southeast-2_ovum4dzAL")
if err != nil {
t.Fatal(err)
}

err = c.createUser(createUserEvent{EmailAddress: "user@example.com"})
if err != nil {
t.Fatal("User should have been created")
}
})
}
错误
Running tool: /usr/local/go/bin/go test -timeout 30s -run ^TestCreateUser$ github.com/sean/repo/src/create_user

--- FAIL: TestCreateUser (0.00s)
--- FAIL: TestCreateUser/Successfully_create_user (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x60 pc=0x137c2f2]

goroutine 6 [running]:
testing.tRunner.func1.1(0x13e00c0, 0x173fd70)
/usr/local/go/src/testing/testing.go:1072 +0x30d
testing.tRunner.func1(0xc000001b00)
/usr/local/go/src/testing/testing.go:1075 +0x41a
panic(0x13e00c0, 0x173fd70)
/usr/local/go/src/runtime/panic.go:969 +0x1b9
github.com/sean/repo/src/create_user.(*mockCreateUser).AdminCreateUser(0xc00000ee40, 0xc00006a200, 0xc00001e39d, 0x18, 0xc0000b24b0)
<autogenerated>:1 +0x32
github.com/sean/repo/src/create_user.(*awsService).createUser(0xc000030738, 0x145bbca, 0x10, 0x18, 0x0)
/Users/sean/code/github/sean/repo/src/create_user/main.go:39 +0x2b7
github.com/sean/repo/src/create_user.TestCreateUser.func1(0xc000001b00)
/Users/sean/code/github/sean/repo/src/create_user/main_test.go:30 +0x10c
testing.tRunner(0xc000001b00, 0x1476718)
/usr/local/go/src/testing/testing.go:1123 +0xef
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:1168 +0x2b3
FAIL github.com/sean/repo/src/create_user 0.543s
FAIL

最佳答案

我认为这里的问题是,您想模拟 AdminCreateUser()方法,但实际上模拟了 CreateUser()方法。
因此,当您创建 mockCreateUser 的新实例时,结构,“实现” cidpif.CognitoIdentityProviderAPI接口(interface),然后调用AdminCreateUser()方法,它没有实现并且失败。
您的main_test.go中的相关代码应该是这样的:

type mockCreateUser struct {
cidpif.CognitoIdentityProviderAPI
Response cidp.AdminCreateUserOutput
}

func (d mockCreateUser) CreateUser(e createUserEvent) error {
return nil
}
添加以下“虚拟”就足够了(并删除 CreateUser() 方法):
func (d mockCreateUser) AdminCreateUser(*cidp.AdminCreateUserInput) (*cidp.AdminCreateUserOutput, error) {
return d.Response, nil
}

此外,我想提出一种稍微不同的方法来对您的 Lambda 进行单元测试。你的代码在可测试性方面已经相当不错了。但你可以做得更好。
我建议创建一个类似于您的 awsService 的“应用程序”。 struct,但不实现任何 AWS 接口(interface)。相反,它包含一个 configuration结构。此配置包含您从环境中读取的值(例如 USER_POOL_IDEMAIL )以及 AWS 服务的实例。
这个想法是您的所有方法和函数都使用此配置,允许您在单元测试期间使用模拟 AWS 服务并在运行时使用“适当的”服务实例。
以下是您的 Lambda 的简化版本。显然,命名等取决于您。还有很多错误处理缺失等。
我认为最大的优势是,您可以通过 config 轻松修改方法/函数的输入。的 application .如果您想在每个测试和不同的行为中使用不同的电子邮件等,您只需更改配置即可。
main.go
package main

import (
"os"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
)

type createUserEvent struct {
EmailAddress string `json:"email_address"`
}

type configuration struct {
poolId string
idp cognitoidentityprovideriface.CognitoIdentityProviderAPI
}

type application struct {
config configuration
}

func (app *application) createUser(event createUserEvent) error {
input := &cognitoidentityprovider.AdminCreateUserInput{
UserPoolId: aws.String(app.config.poolId),
Username: aws.String(event.EmailAddress),
DesiredDeliveryMediums: aws.StringSlice([]string{"EMAIL"}),
ForceAliasCreation: aws.Bool(true),
UserAttributes: []*cognitoidentityprovider.AttributeType{
{
Name: aws.String("email"),
Value: aws.String(event.EmailAddress),
},
},
}

_, err := app.config.idp.AdminCreateUser(input)
if err != nil {
return err
}

return nil
}

func (app *application) handler(event createUserEvent) (events.APIGatewayProxyResponse, error) {
err := app.createUser(event)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}

return events.APIGatewayProxyResponse{}, nil
}

func main() {
config := configuration{
poolId: os.Getenv("USER_POOL_ID"),
idp: cognitoidentityprovider.New(session.Must(session.NewSession())),
}

app := application{config: config}

lambda.Start(app.handler)
}
main_test.go
package main

import (
"testing"

"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
)

type mockAdminCreateUser struct {
cognitoidentityprovideriface.CognitoIdentityProviderAPI
Response *cognitoidentityprovider.AdminCreateUserOutput
Error error
}

func (d mockAdminCreateUser) AdminCreateUser(*cognitoidentityprovider.AdminCreateUserInput) (*cognitoidentityprovider.AdminCreateUserOutput, error) {
return d.Response, d.Error
}

func TestCreateUser(t *testing.T) {
t.Run("Successfully create user", func(t *testing.T) {
idpMock := mockAdminCreateUser{
Response: &cognitoidentityprovider.AdminCreateUserOutput{},
Error: nil,
}

app := application{config: configuration{
poolId: "test",
idp: idpMock,
}}

err := app.createUser(createUserEvent{EmailAddress: "user@example.com"})
if err != nil {
t.Fatal("User should have been created")
}
})
}

关于amazon-web-services - AWS SDK Go Lambda 单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65464240/

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