使用testify/mock模拟Repository测试Golang服务失败求助
问题:Golang单元测试中TestCreatesCommentSuccessfully失败,mock参数不匹配
报错信息
--- FAIL: TestCommentServiceCreateForCreated (0.00s) panic: mock: Unexpected Method Call ----------------------------- Create(*domains.Comment) 0: &domains.Comment{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Comment", Content:"Test Content", PostID:0x7b, Post:domains.Post{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x0, Title:"", Content:"", Published:false}} The closest call I have is: Create(*domains.Comment) 0: &domains.Comment{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Comment", Content:"Test Content", PostID:0x7b, Post:domains.Post{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Post", Content:"Test Content", Published:true}} Difference found in argument 0: --- Expected +++ Actual @@ -24,6 +24,6 @@ }, - ID: (uint) 123, - Title: (string) (len=9) "Test Post", - Content: (string) (len=12) "Test Content", - Published: (bool) true + ID: (uint) 0, + Title: (string) "", + Content: (string) "", + Published: (bool) false } Diff: 0: FAIL: (*domains.Comment=&{{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Comment Test Content 123 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 0 false}}) != (*domains.Comment=&{{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Comment Test Content 123 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Post Test Content true}}) [recovered]
问题根源
查看服务代码的Create方法,创建Comment实例时仅设置了ID、Title、Content、PostID四个字段,未初始化Post字段:
comment := &domains.Comment{ ID: 123, Title: request.Title, Content: request.Content, PostID: request.PostID, }
但测试代码中,给mockRepo.On("Create", mockComment)设置的mockComment却包含了完整的Post对象:
mockComment := &domains.Comment{ ID: 123, Title: request.Title, Content: request.Content, PostID: postId, Post: *mockPost, // 服务代码中并未设置该字段 }
testify/mock默认会进行全字段严格匹配,因此实际调用时传入的Comment(Post字段为默认零值)和测试期望的mockComment不匹配,导致报错。
解决方案
有两种修复方式,任选其一即可:
方式1:让测试期望的Comment与服务实际创建的一致
修改测试代码中的mockComment,去掉Post字段的赋值:
mockComment := &domains.Comment{ ID: 123, Title: request.Title, Content: request.Content, PostID: postId, // 移除 Post: *mockPost 这一行 }
方式2:使用模糊匹配忽略无关字段
如果不需要校验Post字段,可以使用mock.MatchedBy来定义匹配规则,只校验关键字段:
// 替换原有的 mockRepo.On("Create", mockComment) 这一行 mockRepo.On("Create", mock.MatchedBy(func(c *domains.Comment) bool { return c.ID == 123 && c.Title == request.Title && c.Content == request.Content && c.PostID == postId })).Return(nil).Once()
这种方式更灵活,适合只关注核心字段的场景,避免因无关字段默认值导致的匹配失败。
验证修改
修改完成后重新运行测试,TestCreatesCommentSuccessfully即可通过,同时mockRepo.AssertExpectations(t)会验证所有mock方法都按预期被调用。
内容的提问来源于stack exchange,提问作者IamGhale
相关产品推荐
相关产品推荐

