mock类型找不到主因是包路径错位,需在模块根目录运行mockery并用--inpackage;context传参须用mock.anything;gin测试要接口抽象+构造注入;并发测试须避免复用同一mock实例。

mockery生成的Mock类型找不到?包路径错位是主因
最常见编译错误是 undefined: XxxMock,本质是 mockery 推断的包名和模块真实 import 路径不一致。比如接口定义在 github.com/yourorg/app/internal/service,但你在 internal/service 目录下执行命令,它会生成 package service,而 Go 模块要求完整路径导入,导致类型不可见。
- 始终在模块根目录(含
go.mod的目录)下运行mockery命令 - 显式加
--inpackage参数:让生成文件使用当前目录的包名,避免推断偏差 - 跨包引用时加
--recursive,并确认go mod vendor或replace已就绪 - 生成后手动检查生成文件顶部的
package xxx和// import "xxx"是否匹配真实路径
context.Context 传参总不匹配?别传具体实例
mockery 不会自动处理 context.Context 的语义相等性——context.Background() 和 context.TODO() 是不同内存地址的实例,哪怕都“空”,mock.On("Method", ctx, "arg") 也绝不会命中。
- 一律用
mock.Anything占位:mockObj.On("Do", mock.Anything, "arg").Return(nil) - 若必须校验 context 内容(如是否含特定 key),改用
mock.MatchedBy(func(v interface{}) bool { ... }) - 不要在测试中构造新
context传入被测函数再期望它和 mock 中预设的context相等
Gin handler 测试里怎么注入 Mock 依赖?靠接口抽象 + 构造函数注入
Gin handler 本身不直接持有依赖,真正要测的是 handler 封装的业务逻辑(比如 service.UserCreate)。所以必须把依赖抽象成接口,并通过构造函数或字段注入,才能替换为 Mock。
- 定义精简接口,只含业务需要的方法,例如
UserRepository只有Save和GetByID - handler 所属结构体(如
UserHandler)字段类型声明为该接口,而非具体实现 - 测试时 new 出 handler 实例时,传入
mockUserRepo := &MockUserRepository{},而非真实 DB 实例 - 确保 handler 方法内调用的是接口方法,不是硬编码的 struct 方法
测试跑出 data race?别复用同一 Mock 实例
报错指向 mock.calls = append(),基本就是并发调用同一 Mock 实例触发的竞态。mockery 生成的 struct 默认无锁,On()/Return() 和 AssertExpectations() 都操作内部切片 calls。
- 单元测试里禁止用同一个 mock 实例启动多个 goroutine
- 每个 goroutine 应创建独立 mock 实例(哪怕逻辑相同)
- 真需共享状态,手动加
sync.Mutex包裹mockObj.On()等调用 - 或换用
gomock(其Controller默认线程安全)
Mockery 不是魔法,它生成的代码只是工具链一环;真正决定测试可靠性的,是接口设计粒度、依赖注入方式、以及对 context 和并发这些 Go 特性的真实理解。写完生成命令,别急着跑测试——先看一眼生成文件的 package 声明和 import 路径,再检查 handler 是否真的通过接口调用依赖。这两步漏掉,后面所有断言都可能白做。











