【问题标题】:How to mock unit tests for Golang function calling an AWS Service multiple times with different methods?如何使用不同的方法多次模拟调用 AWS 服务的 Golang 函数的单元测试?
【发布时间】:2021-12-28 21:11:54
【问题描述】:

我有以下对 AWS IAM 进行多次调用的函数。我能够在单个调用上运行单元测试。但是,当我在下面的一个上运行测试时,我会感到恐慌:“运行时错误,无效内存或 nil 指针取消引用”

  func (iamDependency *iamService) CreateMyUser(userName string) (string, error){

    //first IAM call
    err:=iamDependency.GetUser(&iam.GetUserInput{UserName: userName})

    if err != nil {

      fmt.Println("Failed to get user, attempting to create")
      
      //second IAM call
      err:=iamDependency.CreateUser(&iam.CreateUserInput{UserName: userName})
  
      if err != nil {
        log.Fatalf("Failed to create user\n", err )
      }
  }
}

这是我的模拟和测试:

type mockSomeOutput{}

type mockedIamCall{
  iamiface.IAMAPI
  Response mockSomeOutput
}

func TestCreateMyUser(t *testing.T){
  t.Run("Successful user create", fun(t *testing.T){
    mo:= mockOutput{}

    m:= mockedIamCall{Response: mo}
    
    d:= iamService{
      iamInstance: m,
    }

   mockedUser:="TestUser"
   
   _, err:= d.ResetCredentials(&mockedUser)
   
   if err != nil {
     t.Fatal("Everything should be ok")
   }
  })
}

我想知道在 Golang 中为这种函数进行单元测试是否有任何技巧或指南。

感谢任何帮助。

【问题讨论】:

    标签: amazon-web-services unit-testing go aws-sdk-go


    【解决方案1】:

    您可能想尝试使用:https://github.com/golang/mock

    您可以为 iamiface.IAMAPI(从实际接口)创建模拟实现,然后期待函数调用并模拟响应。

    使用mockgen 创建接口的模拟实现。

    mockgen -source={path to IAM API interface}
    

    然后你可以在测试用例中期待这样的函数调用:

    function TestExample(t *testing.T) {
      ctrl := gomock.NewController(t)
      mockIAMAPI := mock_package.NewMockIAMAPI(ctrl)
      mockIAMAPI.EXPECT().GetUser(expectedInput).Return(mockResponse).Times(1)
    }
    

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

    @Raymond 感谢您的回复,这很有见地。但是,我似乎找到了一个更简单的答案来解决我自己的问题。我创建了自己的界面

    type UserCreator interface{
      GetUser(*iam.GetUserInput) (*iam.GetUserOutput, error)
      CreateUser(*iam.CreateUserInput) (*iam.CreateUserInput, error)
    }
    
    
    func CreateMyUser(iamSvc UserCreator, userName string) (string, error){
    
        //first IAM call
        _, err:=iamSvc.GetUser(&iam.GetUserInput{UserName: userName})
    
        if err != nil {
    
          fmt.Println("Failed to get user, attempting to create")
          
          //second IAM call
          _, err:=iamSvc.CreateUser(&iam.CreateUserInput{UserName: userName})
      
          if err != nil {
            log.Fatalf("Failed to create user\n", err )
          }
      }
    }
    

    然后对于我的测试,我只是实现接口,覆盖这些方法,并传递一个模拟:

    type mockUserCreator{
      Response string
    }
    
    func (m * mockUserCreator) GetUser(input *iam.GetUserInput)(*iam.GetUserOutput, error){
    return &iam.GetUserOutput{}, nil
    }
    
    func (m * mockUserCreator) CreateUser(input *iam.CreateUserInput)(*iam.CreateUserOutput, error){
    return &iam.CreateUserOutput{}, nil
    }
    
    func TestCreateMyUser(t *testing.T){
      testcases:=[]struct{
       TestName string
      }{
        {
          TestName:"Some test"
        }
      }
      for _, tt := range testcases{
        t.Run(tt.TestName, func(t *testing.T){
          m := mockUserCreator{}
    
         mockUser := "TestUser"
    
          _, err:= CreateMyUser(&m, mockUser)
          
          if err != nil {
            t.Error("TestCreateMyUser returned and error: %s", err)
          }
    
        }
      }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 2020-03-20
      • 2021-07-25
      • 2020-03-17
      • 2020-02-21
      相关资源
      最近更新 更多