Search code examples
unit-testinggomockingtestify

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. My user struct has an ID field is populated by uuid in user service before passing to repository layer. I am mocking the firebase service and repository layer using 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.

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?


Solution

  • 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) . So the arguments will not be considerd and the mock calls will return required value.