dsiv4041
dsiv4041
2018-05-16 18:21
浏览 103
已采纳

我如何对AWS-SDK-GO-V2 DYNAMODB实现进行单元测试

I am still grasping go-interfaces and I can mock the WaitUntilTableExists func. But unable to mock PutItemRequest.

Here's my main.go snippet

func MyPutItem(d mydata, client dynamodbiface.DynamoDBAPI) error {
    input := &dynamodb.PutItemInput{
        ....
    }
    req := client.PutItemRequest(input)
    result, err := req.Send()
    log.Println(result)
    return err
}

main_test.go snippet

type mockDynamoDBClient struct {
    dynamodbiface.DynamoDBAPI
}

func (m *mockDynamoDBClient) PutItemRequest(input *dynamodb.PutItemInput) dynamodb.PutItemRequest {
    // Most probably this is where I need your help
}

func TestStoreInDynamoDB(t *testing.T) {
    var mockClient = new(mockDynamoDBClient)
    d := mydata{}
    result := DynampDBPutItem(d, mockClient)
    t.Log(result)
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • douyu4535
    douyu4535 2018-05-29 13:08
    已采纳

    Faking the SDK like this works:

    main_test.go

    type fakeDynamoDBClient struct {
        dynamodbiface.DynamoDBAPI
    }
    
    func (m *fakeDynamoDBClient) GetItemRequest(input *dynamodb.GetItemInput) dynamodb.GetItemRequest {
        return dynamodb.GetItemRequest{
            Request: &aws.Request{
                Data: &dynamodb.GetItemOutput{
                    Item: map[string]dynamodb.AttributeValue{
                        "count": dynamodb.AttributeValue{
                            N: aws.String("10"),
                        },
                    },
                },
            },
        }
    }
    
    func (m *fakeDynamoDBClient) PutItemRequest(input *dynamodb.PutItemInput) dynamodb.PutItemRequest {
        return dynamodb.PutItemRequest{
            Request: &aws.Request{
                Data: &dynamodb.PutItemOutput{},
            },
        }
    }
    
    func TestUpdateCount(t *testing.T) {
        err := UpdateCount(10, &fakeDynamoDBClient{})
        if err != nil {
            t.Error("Failed to update badge count on dynamodb", err)
        }
    }
    

    main.go

    func UpdateCount(count int, client dynamodbiface.DynamoDBAPI) error {
        ...
    }
    
    点赞 评论
  • doudieheng5322
    doudieheng5322 2018-05-16 19:02

    Taking your example, you could do your assertions directly in the mock

    type mockDynamoDBClient struct {
        t *testing.T
        expected *dynamodb.PutItemInput
        response *dynamodb.PutItemOutput
        dynamodbiface.DynamoDBAPI
    }
    
    func (m *mockDynamoDBClient) PutItemRequest(input *dynamodb.PutItemInput) dynamodb.PutItemOutput {
        // some kind of equality check
        if !reflect.DeepEqual(m.expected, input) {
            t.Errorf(...// some error message)
        }
        return m.response
    }
    

    The main problems with this example are:

    t *testing.T, expected *dynamodb.PutItemInput and response response *dynamodb.PutItemOutput all need to be inside the struct which feels messy.

    Instead you could use an anonymous function to do this:

    type mockDynamoDBClient struct {
        f func(input *dynmaodb.PutItemInput) *dynamodb.PutItemOutput
        dynamodbiface.DynamoDBAPI
    }
    
    func (m *mockDynamoDBClient) PutItemRequest(input *dynamodb.PutItemInput) dynamodb.PutItemOutput {
        return m.f(input)
    }
    

    Now in the test code you can make slightly better use of the mock struct:

    m := &mockDynamoDBClient{
        f: func(input *dynamodb.PutItemInput) *dynamodb.PutItemOutput {
            // assertions on input
            // return mock responses
        }
    }
    

    EDIT based on comment:

    You should also consider making your MyPutItem function dependent on the smallest interface possible. If you only need access to the PutItemRequest method then you can create your own interface for that method and use that in MyPutItem

    type MyDynamoPutter interface {
        func (c *DynamoDB) PutItemRequest(input *PutItemInput) PutItemRequest
    }
    

    Then in MyPutItem you can use your own interface:

    func MyPutItem(d mydata, client MyDynamoPutter) error {
        input := &dynamodb.PutItemInput{
            ....
        }
        req := client.PutItemRequest(input)
        result, err := req.Send()
        log.Println(result)
        return err
    }
    

    This reduces the surface area that you need to mock!

    点赞 评论

相关推荐