简体   繁体   English

使用 testify 检查 go 结构中字段的动态值

[英]Check dynamic value for field in struct in go using testify

I have a user service that validates the user data and formats it and then calls Firebase service which creates a firebase user and return firebase id and then it pass that user data to repository layer.我有一个user service ,它验证用户数据并对其进行格式化,然后调用 Firebase 服务,该服务创建一个 firebase 用户并返回repository id,然后将其传递给数据层。 My user struct has an ID field is populated by uuid in user service before passing to repository layer.我的用户结构有一个ID字段,在传递到repository层之前由user service中的uuid填充。 I am mocking the firebase service and repository layer using strecher/testify .我是 mocking firebase 服务和存储库层使用strecher/testify But the test is failing since the ID is populated by service layer and I cannot pass the ID to the user data used by mock function.但测试失败,因为ID由服务层填充,我无法将ID传递给模拟 function 使用的用户数据。

user := model.User{
        ID:         "",
        FirebaseID: "",
        FirstName: "Test",
        LastName:  "User",
        FullName:  "Test User",
        Email:     "testuser@email.com"
        Password: "password",
    }

Service layer code服务层代码

func (u userService) CreateUser(user model.User) error {
  err := validateFields(user)
  if err != nil {
      return fmt.Errorf("userService CreateUser: %w", err)
  }

  user.FullName = user.FirstName + " " + user.LastName
  user.FirebaseID, err = u.authClient.CreateUser(user)
  if err != nil {
      return fmt.Errorf("userService CreateUser: %w", err)
  }

  user.ID = uuid.NewString()
  err = u.userRepo.CreateUser(user)
  if err != nil {
      return fmt.Errorf("userService CreateUser: %w", err)
  }

return nil

} }

Test code测试代码

func TestCreateUser(t *testing.T) {
  mockFirebaseAuthClient := new(MockFirebaseAuthClient)
  mockPostgresRepo := new(MockPostgresRepo)
  userService := NewUserService(mockPostgresRepo, mockFirebaseAuthClient)

  t.Run("Valid data", func(t *testing.T) {
      user := model.User{
        ID:         "",
        FirebaseID: "firebaseuniqueid",
        FirstName: "Test",
        LastName:  "User",
        FullName:  "Test User",
        Email:     "testuser@email.com",
        Password: "password",
      }
      mockFirebaseAuthClient.On("CreateUser", user).Return("firebaseuniqueid", nil)
      mockPostgresRepo.On("CreateUser", user).Return(nil)
      err := userService.CreateUser(user)
      if err != nil {
          t.Fatalf("Expectd: nil, got: %v", err)
      }
})

Error while testing测试时出错

mock: Unexpected Method Call
-----------------------------

CreateUser(model.User)
        0: model.User{ID:"f87fd2f3-5801-4359-a565-a4eb13a6de37", FirebaseID:"firebaseuniqueid", FirstName:"Test", LastName:"User", FullName:"Test User", Email:"testuser@email.com", Password:"password"}

The closest call I have is: 

CreateUser(model.User)
        0: model.User{ID:"", FirebaseID:"firebaseuniqueid", FirstName:"Test", LastName:"User", FullName:"Test User", Email:"testuser@email.com", Password:"password"}

Difference found in argument 0:

--- Expected
+++ Actual
@@ -1,3 +1,3 @@
 (model.User) {
- ID: (string) "",
+ ID: (string) (len=36) "f87fd2f3-5801-4359-a565-a4eb13a6de37",
  FirebaseID: (string) (len=16) "firebaseuniqueid",

Diff: 0: FAIL:  (model.User={f87fd2f3-5801-4359-a565-a4eb13a6de37 firebaseuniqueid Test User Test User testuser@email.com  password}) != (model.User={ firebaseuniqueid Test User Test User testuser@email.com  password}) [recovered]

Is there any way I could check the dynamically created uuid or ignore the values in the struct in the test?有什么方法可以检查动态创建的 uuid 或忽略测试中结构中的值?

if you don't want to consider mockFirebaseAuthClient.On("CreateUser", user).Return("firebaseuniqueid", nil) and mockPostgresRepo.On("CreateUser", user).Return(nil) and just want to mock that calls, then you can use mock.Anything as the argument in both the calls instead of user like this mockFirebaseAuthClient.On("CreateUser", mock.Anything).Return("firebaseuniqueid", nil) .如果您不想考虑mockFirebaseAuthClient.On("CreateUser", user).Return("firebaseuniqueid", nil)mockPostgresRepo.On("CreateUser", user).Return(nil)并且只想模拟调用,那么您可以在两个调用中使用mock.Anything作为参数,而不是像这样的user mockFirebaseAuthClient.On("CreateUser", mock.Anything).Return("firebaseuniqueid", nil) So the arguments will not be considerd and the mock calls will return required value.所以 arguments 将不被考虑,模拟调用将返回所需的值。

Regarding your question of关于你的问题

Since uuid is not injected into the service layer, how can it be mocked?既然uuid没有注入到服务层,那怎么mock呢? It is an imported package.是进口的package。

Like this, first, define an interface with the same method we want to mock像这样,首先,定义一个与我们要模拟的方法相同的接口

type uuidGen interface {
    String() string
}

Then, define a mock type in which we're going to define our method然后,定义一个模拟类型,我们将在其中定义我们的方法

type mockGen struct{}

Then, define the method on the type然后,在类型上定义方法

func (u *mockGen) String() string {
    return "test"
}

Update CreateUser function to receive a uuidGen parameter that shares the method String() with uuid 's package.更新CreateUser function 以接收与uuid的 package 共享方法String()uuidGen参数。

func (u userService) CreateUser(uuid uuidGen, user User) error {
    err := validateFields(user)
    if err != nil {
        return fmt.Errorf("userService CreateUser: %w", err)
    }
    user.FullName = user.FirstName + " " + user.LastName
    user.FirebaseID, err = u.authClient.CreateUser(user)
    if err != nil {
        return fmt.Errorf("authClient CreateUser: %w", err)
    }
    user.ID = uuid.String()
    err = u.userRepo.CreateUser(user)
    if err != nil {
        return fmt.Errorf("userService CreateUser: %w", err)
    }
    return nil
}

Now we can write the test like this, see how the 2 methods accept different types that implement the interface uuidGen and can call a method String()现在我们可以这样写测试,看看这2个方法如何接受实现接口uuidGen的不同类型并且可以调用方法String()

func TestCreateUser(t *testing.T) {
    mockFirebaseAuthClient := new(MockFirebaseAuthClient)
    mockPostgresRepo := new(MockPostgresRepo)
    userService := NewUserService("test", "test")

    t.Run("Valid data", func(t *testing.T) {
            user := User{
                    ID:         "",
                    FirebaseID: "firebaseuniqueid",
                    FirstName:  "Test",
                    LastName:   "User",
                    FullName:   "Test User",
                    Email:      "testuser@email.com",
                    Password:   "password",
            }
            mockFirebaseAuthClient.On("CreateUser", user).Return("firebaseuniqueid", nil)
            mockPostgresRepo.On("CreateUser", user).Return(nil)
            gen := new(mockGen)
            err := userService.CreateUser(gen, user)
            if err != nil {
                    t.Fatalf("Expectd: nil, got: %v", err)
            }
            realUUID := uuid.New()
            err = userService.CreateUser(realUUID, user)
            if err != nil {
                    t.Fatalf("Expectd: nil, got: %v", err)
            }
            t.Log("Mock UUID:", gen.String())  // prints test
            t.Log("Real UUID UUID:", realUUID.String()) // prints a UUID
    })
}

Run it with go test -v to see the output of t.Log(...)使用go test -v运行它以查看t.Log(...)的 output

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM