在测试Golang AWS Lambdas时,可以在模拟外部函数的同时重用代码。

huangapple go评论151阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年2月13日 22:46:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75437415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定