代码之家  ›  专栏  ›  技术社区  ›  Sara Fuerst

是否可以在不更改参数的情况下对使用AWS SDK的Go函数进行单元测试?

  •  1
  • Sara Fuerst  · 技术社区  · 6 年前

    我刚开始写了一个函数,它使用AWS机密管理器获取机密:

    //Helper function to get secret from AWS Secret Manager
    func getAWSSecrets() (secretMap map[string]string, err error) {
        // Create new AWS session in order to get db info from SecretsManager
        sess, err := session.NewSession()
        if err != nil {
            return nil, err
        }
    
        // Create a new instance of the SecretsManager client with session
        svc := secretsmanager.New(sess)
    
        //Get secret config values
        req, resp := svc.GetSecretValueRequest(&secretsmanager.GetSecretValueInput{
            SecretId: aws.String("my/secret/string"),
        })
    
        err = req.Send()
        if err != nil {
            return nil, err
        }
    
        ...
    }
    

    我需要为函数创建一个单元测试,为此我需要模拟AWS机密管理器。我发现了一个 Secrets Manager Interface that AWS was created to help with unit testing . 在显示的示例中,将把AWS Secrets Manager传递到正在测试的函数中,这样就很容易在模拟服务中传递。这是成功单元测试功能的唯一方法吗?或者服务可以在我上面的功能中被模仿吗?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Carlos Frias    6 年前

    正如注释所说,使函数调用成为一个方法,并利用AWS提供的接口。

    我将创建一个服务,如:

    package service
    
    type SecretService struct {
        AwsProvider aws.SecretsManagerAPI
    }
    
    func NewSecretService() (*SecretService, err) {
        // Create new AWS session in order to get db info from SecretsManager
        sess, err := session.NewSession()
        if err != nil {
            return nil, err
        }
    
        return &SecretService{
            AwsProvider: secretsmanager.New(sess),
        }, nil
    }
    
    func (s *SecretService) GetAWSSecrets() {
        req, resp := s.AwsProvider.GetSecretValueRequest(&secretsmanager.GetSecretValueInput{
            SecretId: aws.String("my/secret/string"),
        })
    
        err = req.Send()
        if err != nil {
            return nil, err
        }
    
        // More magic below ...
    }
    

    这样,在测试中,我可以通过任何模拟进入SecretService,如下所示:

    func TestSecretService_GetAWSSecrets(t *testing.T) {
      service := &service.SecretService{
        AwsProvider: <use your mock here>
      }
    }
    

    一个警告是,我猜模拟必须实现SecretsManagerAPI的所有方法,我认为对于这个简单的场景来说,这是一个很大的工作…在任何情况下,您都可以在服务包中创建自己的接口,只使用将要使用的方法的子集,比如说,您将只使用 GetSecretValueRequest CreateSecret :

    package service
    
    type SecretProvider interface {
        CreateSecret(*secretsmanager.CreateSecretInput) (*secretsmanager.CreateSecretOutput, error)
        GetSecretValueRequest(*secretsmanager.GetSecretValueInput) (*request.Request, *secretsmanager.GetSecretValueOutput)
    }
    

    更改服务:

    type SecretService struct {
        AwsProvider SecretProvider
    }
    

    现在您的模拟只需要实现SecretProvider接口方法。当然,aws secretsmanager隐式地实现secretprovider。