如何使用不同的方法模拟多次调用 AWS 服务的 Golang 函数的单元测试?

How to mock unit tests for Golang function calling an AWS Service multiple times with different methods?

我有以下函数可以多次调用 AWS IAM。我能够 运行 对单个调用进行单元测试。然而,当我 运行 对下面的测试进行测试时,我感到恐慌:"运行time error, invalid memory or nil pointer dereference"

  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 中对这种功能进行单元测试是否有任何技巧或指南。

感谢任何帮助。

您可能想尝试使用: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)
}

@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)
      }

    }
  }
}