AWS SDK Go Lambda 单元测试

我第一次尝试全神贯注地编写一些单元测试,并且我正在 golang 中为使用 aws lambda 的辅助项目做这件事。

下面是两个文件。

main.go接受一个包含电子邮件地址的事件,并在认知用户池中创建用户。

main_test.go应该模拟中的createUser函数main.go,但是当我尝试运行测试时出现错误。

观看此 youtube 视频后,我刚刚将我的代码从全局实例化客户端切换为在 aws sdk 接口上使用指针接收器方法。

错误


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



桃花长相依
浏览 101回答 1
1回答

白衣非少年

我认为这里的问题是,您想模拟该AdminCreateUser()方法,但实际上确实模拟了该CreateUser()方法。因此,当您创建mockCreateUser结构的新实例时,“实现”cidpif.CognitoIdentityProviderAPI接口,然后调用它的AdminCreateUser()方法,它没有实现并且失败。你的相关代码main_test.go应该是这样的:type mockCreateUser struct {&nbsp; &nbsp; cidpif.CognitoIdentityProviderAPI&nbsp; &nbsp; Response cidp.AdminCreateUserOutput}func (d mockCreateUser) CreateUser(e createUserEvent) error {&nbsp; &nbsp; return nil}CreateUser()添加以下“虚拟”(并删除该方法)就足够了:func (d mockCreateUser) AdminCreateUser(*cidp.AdminCreateUserInput) (*cidp.AdminCreateUserOutput, error) {&nbsp; &nbsp; return d.Response, nil}此外,我想提出一种稍微不同的方法来对您的 Lambda 进行单元测试。你的代码在可测试性方面已经相当不错了。但你可以做得更好。我建议创建一个与您的awsService结构类似的“应用程序”,但不实现任何 AWS 接口。相反,它包含一个configuration结构。此配置包含您从环境中读取的值(例如USER_POOL_ID, EMAIL)以及 AWS 服务的实例。这个想法是您的所有方法和函数都使用此配置,允许您在单元测试期间使用模拟 AWS 服务并在运行时使用“适当的”服务实例。以下是您的 Lambda 的简化版本。显然,命名等取决于您。还有很多错误处理缺失等。我认为最大的优势是,您可以config通过application. 如果您想在每个测试和不同的行为中使用不同的电子邮件等,您只需更改配置即可。main.gopackage mainimport (&nbsp; &nbsp; "os"&nbsp; &nbsp; "github.com/aws/aws-lambda-go/events"&nbsp; &nbsp; "github.com/aws/aws-lambda-go/lambda"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/aws"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/aws/session"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface")type createUserEvent struct {&nbsp; &nbsp; EmailAddress string `json:"email_address"`}type configuration struct {&nbsp; &nbsp; poolId string&nbsp; &nbsp; idp&nbsp; &nbsp; cognitoidentityprovideriface.CognitoIdentityProviderAPI}type application struct {&nbsp; &nbsp; config configuration}func (app *application) createUser(event createUserEvent) error {&nbsp; &nbsp; input := &cognitoidentityprovider.AdminCreateUserInput{&nbsp; &nbsp; &nbsp; &nbsp; UserPoolId:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aws.String(app.config.poolId),&nbsp; &nbsp; &nbsp; &nbsp; Username:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aws.String(event.EmailAddress),&nbsp; &nbsp; &nbsp; &nbsp; DesiredDeliveryMediums: aws.StringSlice([]string{"EMAIL"}),&nbsp; &nbsp; &nbsp; &nbsp; ForceAliasCreation:&nbsp; &nbsp; &nbsp;aws.Bool(true),&nbsp; &nbsp; &nbsp; &nbsp; UserAttributes: []*cognitoidentityprovider.AttributeType{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Name:&nbsp; aws.String("email"),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Value: aws.String(event.EmailAddress),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; }&nbsp; &nbsp; _, err := app.config.idp.AdminCreateUser(input)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; return nil}func (app *application) handler(event createUserEvent) (events.APIGatewayProxyResponse, error) {&nbsp; &nbsp; err := app.createUser(event)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return events.APIGatewayProxyResponse{}, err&nbsp; &nbsp; }&nbsp; &nbsp; return events.APIGatewayProxyResponse{}, nil}func main() {&nbsp; &nbsp; config := configuration{&nbsp; &nbsp; &nbsp; &nbsp; poolId: os.Getenv("USER_POOL_ID"),&nbsp; &nbsp; &nbsp; &nbsp; idp:&nbsp; &nbsp; cognitoidentityprovider.New(session.Must(session.NewSession())),&nbsp; &nbsp; }&nbsp; &nbsp; app := application{config: config}&nbsp; &nbsp; lambda.Start(app.handler)}main_test.gopackage mainimport (&nbsp; &nbsp; "testing"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"&nbsp; &nbsp; "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface")type mockAdminCreateUser struct {&nbsp; &nbsp; cognitoidentityprovideriface.CognitoIdentityProviderAPI&nbsp; &nbsp; Response *cognitoidentityprovider.AdminCreateUserOutput&nbsp; &nbsp; Error&nbsp; &nbsp; error}func (d mockAdminCreateUser) AdminCreateUser(*cognitoidentityprovider.AdminCreateUserInput) (*cognitoidentityprovider.AdminCreateUserOutput, error) {&nbsp; &nbsp; return d.Response, d.Error}func TestCreateUser(t *testing.T) {&nbsp; &nbsp; t.Run("Successfully create user", func(t *testing.T) {&nbsp; &nbsp; &nbsp; &nbsp; idpMock := mockAdminCreateUser{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Response: &cognitoidentityprovider.AdminCreateUserOutput{},&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Error:&nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; app := application{config: configuration{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; poolId: "test",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idp:&nbsp; &nbsp; idpMock,&nbsp; &nbsp; &nbsp; &nbsp; }}&nbsp; &nbsp; &nbsp; &nbsp; err := app.createUser(createUserEvent{EmailAddress: "user@example.com"})&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.Fatal("User should have been created")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go