gomock mock类型报“undefined”因未导入生成包;context匹配失败因默认指针比较,需用gomock.any();多测试复用controller会残留期望;泛型接口不支持是工具限制。

gomock 生成的 mock 类型为什么总报 “undefined”?
因为 gomock 生成的 mock 结构体默认放在独立包里,而你没导入它。常见现象是编译报错:undefined: mock_xxx.MockSomething。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
mockgen时显式指定-destination和-package,避免默认生成到临时包名(如mocks);推荐统一放在项目内mocks/目录下,并设-package=mocks - 生成后,确保测试文件 import 了该 mock 包,例如:
import "your-project/mocks" - 别用
go:generate时漏掉-source路径——如果接口定义在pkg/api/interface.go,就得写mockgen -source=pkg/api/Interface.go,相对路径错一位就找不到接口
interface 方法带 context.Context 时,mock.Expect() 怎么写才不 panic?
因为 gomock 默认对 context.Context 做指针比较,而每次调用都新建一个 context.background() 或 context.WithTimeout(),导致匹配失败,mock.ExpectedCalls 没被满足,最终 test panic 报 “call is not expected”。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
gomock.Any()替代具体 context 实例,例如:mockObj.EXPECT().DoSomething(gomock.Any(), gomock.Eq("arg")).Return(nil) - 如果必须校验 context 属性(比如是否含特定 value),改用
gomock.AssignableToTypeOf(&context.Context{})+ 自定义 matcher,但多数场景没必要 - 注意:不要在 Expect 中直接传
context.TODO()或context.Background()—— 它们每次都是新地址,无法通过默认的Eq匹配
多个测试共用同一个 mock 对象时,为什么第二次 test 就 fail?
因为 gomock.Controller 是有状态的,它记录了所有 EXPECT() 和实际调用,且不自动重置。如果复用 controller(比如定义为全局变量或 Struct field),前一个 test 的 expect 会残留,干扰后续 test。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 每个 test 函数内创建独立
gomock.NewController(t),并在函数末尾 deferctrl.Finish() - 不要把
ctrl或 mock 实例缓存在init()、包级变量或 test helper 函数外的作用域里 - 如果要用 table-driven test,确保每轮迭代都 new 一个 controller ——
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t); ... }) }
gomock 生成的 mock 不支持泛型接口?
是的,截至 gomock v1.8.0(当前主流版本),mockgen 无法解析含类型参数的 interface,会静默跳过或报 parse Error。这不是你写错了,是工具限制。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 暂时绕过方式:把泛型接口“具化”成一个非泛型 interface,仅用于 mock,例如定义
type MockableReader interface { Read([]byte) (int, error) },再让泛型结构体实现它 - 不要尝试用
//go:generate对含[T any]的文件跑mockgen—— 它不会报错,但也不会生成任何东西,容易误以为成功 - 关注 gomock#659,目前社区方案仍是手写轻量 mock 或换用
gomonkey等 patch 方案,但代价是失去类型安全
gomock 的边界其实很清晰:它只 mock 接口,不碰实现;只管调用顺序和参数,不管内部逻辑分支。一旦开始纠结“怎么 mock 一个方法里的 goroutine”或者“怎么验证 channel 发了多少次”,说明已经踩出它的设计半径了。