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

Posted

技术标签:

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

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

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

    //first IAM call
    err:=iamDependency.GetUser(&iam.GetUserInputUserName: userName)

    if err != nil 

      fmt.Println("Failed to get user, attempting to create")
      
      //second IAM call
      err:=iamDependency.CreateUser(&iam.CreateUserInputUserName: 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:= mockedIamCallResponse: mo
    
    d:= iamService
      iamInstance: m,
    

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

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

感谢任何帮助。

【问题讨论】:

【参考方案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.GetUserInputUserName: userName)

    if err != nil 

      fmt.Println("Failed to get user, attempting to create")
      
      //second IAM call
      _, err:=iamSvc.CreateUser(&iam.CreateUserInputUserName: 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)
      

    
  


【讨论】:

以上是关于如何使用不同的方法多次模拟调用 AWS 服务的 Golang 函数的单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 aws 检查器资源组上多次使用相同的标签

AWS Cognito 模拟

如何使用 Mockery 在模拟方法的第 N 次调用中引发异常

如何在 React Native 的初始渲染中多次调用组件的 prop 方法?

我多次调用相同的服务(AFNetworking)

如何管理在开发(而非测试)环境中使用多个微服务并对其进行模拟?