英文:
Reuse code while mocking external funcs when testing golang aws lambdas
问题
我有一个使用AWS Lambda的Golang应用程序。我想为它编写单元测试。
这是测试代码:
func TestHandleLambdaEvent(t *testing.T) {
ctx := context.TODO()
//mockNewAuthContextWithMap()
oldNewAuthContextWithMap := NewAuthContextWithMap
defer func() { NewAuthContextWithMap = oldNewAuthContextWithMap }()
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
//mockLambdaInvoke()
old := LambdaInvoke
defer func() { LambdaInvoke = old }()
LambdaInvoke = func(context context.Context, arn string, request, response interface{}) error { return nil }
resp, err := handleLambdaEvent(ctx, events.APIGatewayProxyRequest{})
if err != nil {
t.Fatalf("handleLambdaEvent returned error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("Invalid status code, provded: %d required %d", resp.StatusCode, http.StatusOK)
}
}
这段测试代码运行良好,但是我想将代码放在mockNewAuthContextWithMap
函数中,然后从测试中调用它。但是这样不起作用。我猜是因为defer
函数在测试调用处理程序之前运行。
我该如何修复它?看起来我可以重用这部分代码:
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
但是使用defer
函数保存旧的函数值并回滚它必须重复进行。
编辑:
可能我唯一能做的就是:
func TestHandleLambdaEvent(t *testing.T) {
ctx := context.TODO()
mockNewAuthContextWithMap()
mockLambdaInvoke()
resp, err := handleLambdaEvent(ctx, events.APIGatewayProxyRequest{})
if err != nil {
t.Fatalf("handleLambdaEvent returned error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("Invalid status code, provded: %d required %d", resp.StatusCode, http.StatusOK)
}
defer RollbackExternalMethods()
}
// LambdaInvoke
func mockNewAuthContextWithMap() {
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
}
// LambdaInvoke
func mockLambdaInvoke() {
LambdaInvoke = func(context context.Context, arn string, request, response interface{}) error { return nil }
}
func RollbackExternalMethods() {
NewAuthContextWithMap = authutils.NewAuthContextWithMap
LambdaInvoke = lambdaClient.Invoke
}
编辑:handleLambdaEvent
func handleLambdaEvent(context context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
authContext, err := NewAuthContextWithMap(request.RequestContext.Authorizer)
if err != nil {
fmt.Println("Error parsing auth context:", err)
return awsutils.StatusResponse(http.StatusInternalServerError), nil
}
queryRequest := handlerInput.GetProfile{
Type: handlerInput.TypeGetProfile,
UserId: authContext.UserID,
}
queryResp := dbModel.User{}
err = LambdaInvoke(context, userServiceArn, queryRequest, &queryResp)
if err != nil {
if ierrError, ok := err.(ierr.Error); ok {
if ierrError.IsSame(user.RecordNotFoundError) {
fmt.Printf("Could not find user profile of userId: %s \n", authContext.UserID)
emptyResp := dbModel.User{}
return awsutils.SwaggerResponse(http.StatusOK, emptyResp.SwaggerModel()), nil
}
}
fmt.Println("Error invoking lambda:", err)
return awsutils.StatusResponse(http.StatusInternalServerError), nil
}
swagUser := queryResp.SwaggerModel()
return awsutils.SwaggerResponse(http.StatusOK, swagUser), nil
}
英文:
I have AWS lambdas in my golang app.
Wanted to write unit tests for it:
func TestHandleLambdaEvent(t *testing.T) {
ctx := context.TODO()
//mockNewAuthContextWithMap()
oldNewAuthContextWithMap := NewAuthContextWithMap
defer func() { NewAuthContextWithMap = oldNewAuthContextWithMap }()
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
//mockLambdaInvoke()
old := LambdaInvoke
defer func() { LambdaInvoke = old }()
LambdaInvoke = func(context context.Context, arn string, request, response interface{}) error { return nil }
resp, err := handleLambdaEvent(ctx, events.APIGatewayProxyRequest{})
if err != nil {
t.Fatalf("handleLambdaEvent returned error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("Invalid status code, provded: %d required %d", resp.StatusCode, http.StatusOK)
}
}
this test code works fine, but.. I would like to put code under mockNewAuthContextWithMap to func ie:
func mockNewAuthContextWithMap() {
old := NewAuthContextWithMap
defer func() { NewAuthContextWithMap = old }()
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
}
and simply call it from the test. Then it does not work.
I assume its due to defer func, which simply run before test will call handler.
how can I fix it ?
looks like I can reuse this part of code:
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
but saving old function value with defer func that will rollback it must be repeated everytime.
EDIT:
probably only what I can do is:
func TestHandleLambdaEvent(t *testing.T) {
ctx := context.TODO()
mockNewAuthContextWithMap()
mockLambdaInvoke()
resp, err := handleLambdaEvent(ctx, events.APIGatewayProxyRequest{})
if err != nil {
t.Fatalf("handleLambdaEvent returned error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("Invalid status code, provded: %d required %d", resp.StatusCode, http.StatusOK)
}
defer RollbackExternalMethods()
}
// LambdaInvoke
func mockNewAuthContextWithMap() {
NewAuthContextWithMap = func(stringifiedMap map[string]interface{}) (*authutils.AuthContext, error) {
return &authutils.AuthContext{UserID: "12345", Org: "XYZOrg", Role: "Member", Timestamp: 999999999}, nil
}
}
// LambdaInvoke
func mockLambdaInvoke() {
LambdaInvoke = func(context context.Context, arn string, request, response interface{}) error { return nil }
}
func RollbackExternalMethods() {
NewAuthContextWithMap = authutils.NewAuthContextWithMap
LambdaInvoke = lambdaClient.Invoke
}
EDIT: handleLambdaEvent
func handleLambdaEvent(context context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
authContext, err := NewAuthContextWithMap(request.RequestContext.Authorizer)
if err != nil {
fmt.Println("Error parsing auth context:", err)
return awsutils.StatusResponse(http.StatusInternalServerError), nil
}
queryRequest := handlerInput.GetProfile{
Type: handlerInput.TypeGetProfile,
UserId: authContext.UserID,
}
queryResp := dbModel.User{}
err = LambdaInvoke(context, userServiceArn, queryRequest, &queryResp)
if err != nil {
if ierrError, ok := err.(ierr.Error); ok {
if ierrError.IsSame(user.RecordNotFoundError) {
fmt.Printf("Could not find user profile of userId: %s \n", authContext.UserID)
emptyResp := dbModel.User{}
return awsutils.SwaggerResponse(http.StatusOK, emptyResp.SwaggerModel()), nil
}
}
fmt.Println("Error invoking lambda:", err)
return awsutils.StatusResponse(http.StatusInternalServerError), nil
}
swagUser := queryResp.SwaggerModel()
return awsutils.SwaggerResponse(http.StatusOK, swagUser), nil
}
答案1
得分: 1
https://github.com/stretchr/testify#suite-package
testify具有诸如before、after test等的很好的功能。通过使用它,可以轻松避免复制粘贴代码的相同部分。
英文:
https://github.com/stretchr/testify#suite-package
testify has nice features like before, after test etc. by using this its easy to avoid copy pasting the sam parts of code
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论