如何使用不同的方法模拟多次调用 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)
}
}
}
}
我有以下函数可以多次调用 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)
}
}
}
}