You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何Mock AWS SDK for Go调用?SecretsManager单元测试遇阻

如何Mock AWS Secrets Manager的GetSecretValueRequest及Send方法(Go语言)

我明白你现在卡在Mock AWS SDK的GetSecretValueRequest返回的req对象,以及模拟req.Send()的行为上了。其实不用太纠结于构建完整的request.Request对象,我们有两种简单的实现思路,要么适配你现有的代码做Mock,要么稍微调整代码让Mock更轻松。


方案一:适配现有代码的Mock实现

如果不想修改getAWSSecrets的现有逻辑,我们可以通过自定义Mock请求的处理逻辑来模拟Send()的行为。核心是利用AWS SDK请求的Handlers字段注入自定义逻辑:

1. 完善Mock客户端结构

import (
    "errors"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/client"
    "github.com/aws/aws-sdk-go/aws/request"
    "github.com/aws/aws-sdk-go/service/secretsmanager"
    "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
)

type MockSecretsManagerClient struct {
    secretsmanageriface.SecretsManagerAPI
    // 预设的响应和错误,用于控制测试结果
    ExpectedSecret *secretsmanager.GetSecretValueOutput
    ExpectedErr    error
}

// 自定义GetSecretValueRequest的Mock实现
func (m *MockSecretsManagerClient) GetSecretValueRequest(input *secretsmanager.GetSecretValueInput) (*request.Request, *secretsmanager.GetSecretValueOutput) {
    // 创建基础请求实例,传入空配置和客户端(测试用无需真实配置)
    cfg := &aws.Config{}
    client := &client.Client{}
    req := request.New(cfg, client, nil, request.Handlers{}, input, m.ExpectedSecret, nil)

    // 注入自定义的Send处理逻辑
    req.Handlers.Send.PushBack(func(r *request.Request) {
        if m.ExpectedErr != nil {
            r.Error = m.ExpectedErr
            return
        }
        // 若无错误,将预设响应赋值给请求的Data字段
        r.Data = m.ExpectedSecret
    })

    return req, m.ExpectedSecret
}

2. 编写测试用例

现在可以分别测试成功和失败的场景:

func (suite *ServerTestSuite) TestGetAWSSecrets_Success() {
    // 预设成功的密钥响应
    mockSecret := &secretsmanager.GetSecretValueOutput{
        SecretString: aws.String(`{"username":"test_user","password":"test_pass123"}`),
    }
    mockSvc := &MockSecretsManagerClient{
        ExpectedSecret: mockSecret,
        ExpectedErr:    nil,
    }

    secretMap, err := getAWSSecrets(mockSvc)

    // 断言结果符合预期
    suite.NoError(err)
    suite.Equal("test_user", secretMap["username"])
    suite.Equal("test_pass123", secretMap["password"])
}

func (suite *ServerTestSuite) TestGetAWSSecrets_Failure() {
    // 预设获取密钥失败的错误
    mockErr := errors.New("access denied to secret")
    mockSvc := &MockSecretsManagerClient{
        ExpectedSecret: nil,
        ExpectedErr:    mockErr,
    }

    secretMap, err := getAWSSecrets(mockSvc)

    // 断言错误和空结果
    suite.ErrorIs(err, mockErr)
    suite.Nil(secretMap)
}

方案二:调整代码简化Mock(更推荐)

如果可以稍微修改getAWSSecrets的实现,直接使用GetSecretValue方法(而非GetSecretValueRequest),Mock会变得异常简单,因为这个方法直接返回响应和错误,不需要处理请求对象:

1. 修改main.go中的函数逻辑

// Helper function to get secret from AWS Secret Manager
func getAWSSecrets(svc secretsmanageriface.SecretsManagerAPI) (secretMap map[string]string, err error) {
    // 直接调用GetSecretValue,而非GetSecretValueRequest
    resp, err := svc.GetSecretValue(&secretsmanager.GetSecretValueInput{
        SecretId: aws.String("my/secret/string"),
    })
    if err != nil {
        return nil, err
    }
    // 解析SecretString到secretMap的逻辑(保持原有代码不变)
    ...
}

2. 简化Mock客户端实现

type MockSecretsManagerClient struct {
    secretsmanageriface.SecretsManagerAPI
    ExpectedSecret *secretsmanager.GetSecretValueOutput
    ExpectedErr    error
}

// Mock GetSecretValue方法,直接返回预设值
func (m *MockSecretsManagerClient) GetSecretValue(input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) {
    return m.ExpectedSecret, m.ExpectedErr
}

3. 测试用例写法和方案一类似

同样可以轻松测试成功、失败等各种场景,代码结构更简洁,维护成本更低。


内容的提问来源于stack exchange,提问作者Sara Fuerst

火山引擎 最新活动