1

我有一个user service验证用户数据并对其进行格式化的方法,然后调用 Firebase 服务,该服务创建一个 firebase 用户并返回 firebase id,然后将该用户数据传递给repository层。我的用户结构有一个字段 在传递到层之前IDuuidin填充。我正在使用. 但是测试失败了,因为它是由服务层填充的,我无法将它传递给模拟函数使用的用户数据。user servicerepositorystrecher/testifyIDID

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

服务层代码

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

}

测试代码

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

测试时出错

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]

有什么方法可以检查动态创建的 uuid 或忽略测试中结构中的值?

4

2 回答 2

1

如果您不想考虑mockFirebaseAuthClient.On("CreateUser", user).Return("firebaseuniqueid", nil)并且mockPostgresRepo.On("CreateUser", user).Return(nil)只想模拟该调用,那么您可以mock.Anything在两个调用中用作参数,而不是user像 this 那样mockFirebaseAuthClient.On("CreateUser", mock.Anything).Return("firebaseuniqueid", nil)。因此不会考虑参数,并且模拟调用将返回所需的值。

于 2021-12-19T14:46:24.197 回答
0

关于你的问题

既然uuid没有注入到服务层,那怎么mock呢?它是一个进口包。

像这样,首先,定义一个与我们要模拟的方法相同的接口

type uuidGen interface {
    String() string
}

然后,定义一个模拟类型,我们将在其中定义我们的方法

type mockGen struct{}

然后,在类型上定义方法

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

更新CreateUser函数以接收与' 包uuidGen共享方法的参数。String()uuid

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
}

现在我们可以这样写测试,看看这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
    })
}

运行它go test -v以查看输出t.Log(...)

于 2021-12-19T16:39:12.337 回答