简化 AWS SDK GO v2 测试/模拟

Tim*_*ddy 13 unit-testing mocking go aws-sdk-go-v2

Amazon 有一篇非常有用的文章,描述了如何对AWS SDK Go v2 进行单元测试。我理解他们放弃 v1 API 单元测试的“旧”方式的动机,我认为这与CodeReviewComment一致。

然而,我遇到了一种对我造成严重破坏的情况。

假设我正在打电话s3.HeadObject(),如果满足某些任意条件,我就会打电话s3.GetObject()。因此,我设计了我的 API,以便我可以分别为每个操作创建客户端 API(在pseudoGo 中)。

type HeadObjectAPIClient interface {
    HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error)
}

func GetHeadObject(api HeadObjectAPIClient, params...) (*s3.HeadObjectOutput, error) {
    /* setup logic */
    return api.HeadObject( /* params */ )
}

type GetObjectAPIClient interface {
    GetObject(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error)
}

func GetObject(api GetObjectAPIClient, params...) (*s3.GetObjectOutput, error) {
    /* setup logic */
    return api.GetObject( /* params */ )
}

func DoSomething(headAPI HeadObjectAPIClient, getAPI GetObjectAPIClient, params...) error {
    headOutput, err := GetHeadObject(headAPI, ...params...)
    if err != nil {
        return err
    }
    // process headOutput then ...
    getOutput, err := GetObject(getAPI, ...params...)
    if err != nil {
        return err
    }
    // process getOutput
}
Run Code Online (Sandbox Code Playgroud)

因此,DoSomething除了其他参数之外,该方法还采用两个 API。我的自然倾向是创建某种结构:

type DoSomethingService struct {
    headAPI HeadObjectAPIClient
    getAPI GetObjectAPIClient
}

func (s DoSomethingService) DoSomething(params...) error {
    headOutput, err := GetHeadObject(s.headAPI, ...params...)
    if err != nil {
        return err
    }
    // process headOutput then ...
    getOutput, err := GetObject(s.getAPI, ...params...)
    if err != nil {
        return err
    }
    // process getOutput
}
Run Code Online (Sandbox Code Playgroud)

也许这没问题……但后来我问,为什么不直接制作嵌入式接口并避免使用结构:

type DoSomethingAPIClient interface {
    HeadObjectAPIClient
    GetObjectAPIClient
}

func DoSomething2(api DoSomethingAPIClient, params...) error {
    headOutput, err := GetHeadObject(api, ...params...)
    if err != nil {
        return err
    }
    // process headOutput then ...
    getOutput, err := GetObject(api, ...params...)
    if err != nil {
        return err
    }
    // process getOutput
}
Run Code Online (Sandbox Code Playgroud)

我可能可以想出更多方法来实现这一点,但我想我已经表达了我的观点。

我正在寻找一种好的策略来启用测试/模拟,同时避免每次调用 SDK 时都出现客户端接口激增。