mockery 生成的 mock 文件报 undefined 错误,主因是模块路径与包名不一致导致 package 声明错误;接口含 context.context 时需用 mock.anything 匹配;并发调用 mock 会触发 data race;go:generate 失效常因注释位置、文件命名或版本兼容问题。

mockery 生成的 mock 文件为什么总报错 undefined?
Go 模块路径和接口所在包名不一致时,mockery 默认按当前目录推断包名,容易生成错误的 package 声明。比如接口定义在 github.com/yourorg/app/pkg/service,但你在 pkg/service 目录下运行命令,它可能生成 package service 而非 package service // import "github.com/yourorg/app/pkg/service"。
- 运行前确认当前工作目录是模块根目录(含
go.mod) - 显式指定包路径:
mockery --name=MyInterface --dir=./pkg/service --inpackage - 若接口跨模块,加
--recursive并确保replace或go mod vendor已就绪 - 错误现象常见为:编译时报
undefined: MyInterfaceMock或cannot use ... as ... value in argument
interface 方法带 context.Context 时 mock 行为异常?
mockery 会原样复制方法签名,但若接口方法参数含 context.Context,而你用 mock.Mock.On().Return() 时传了具体值(如 context.Background()),实际调用时传入的是另一个 context 实例,导致匹配失败。
- 用
mock.Anything替代具体context值:mockObj.On("Do", mock.Anything, "arg").Return(nil) - 不要写
mockObj.On("Do", context.Background(), "arg")—— context 实例不可比 - 如果必须校验 context 是否含某 key/value,改用
mock.MatchedBy(func(v interface{}) bool { ... })
mockery 配合 go test -race 报 data race?
mockery 生成的 mock 结构体默认不含同步控制,多个 goroutine 并发调用 On() / Return() 或触发 AssertExpectations() 时,内部计数器(如 calls 切片)会引发竞态。
- 单测中避免并发调用同一 mock 实例的方法;每个 goroutine 应用独立 mock 实例
- 若必须并发,手动加锁包装 mock 调用,或改用
gomock(其Controller默认线程安全) -
go test -race下出现WARNING: DATA RACE指向 mock 生成文件中的mock.calls = append(...),就是这个原因
为什么 go generate + mockery 注释没触发生成?
//go:generate mockery --name=MyInterface 注释生效需同时满足三个条件:注释在接口定义上方、所在文件可被 go list 扫描到、且执行 go generate 时在正确目录。
立即学习“go语言免费学习笔记(深入)”;
- 注释必须紧贴接口定义上一行,中间不能有空行或其它语句
- 接口不能是未导出(小写开头),否则
mockery跳过 - 在模块根目录执行
go generate ./...;若只对某子目录生效,得写go generate ./pkg/service - 常见静默失败:接口在
_test.go文件里(默认被忽略),或mockery版本太老不支持 Go 1.21+ 的嵌入式接口语法
mock 本质是契约快照,不是运行时代理。一旦接口签名变更,旧 mock 不报错但行为失效——这点比类型检查更难察觉。










