mockgen命令必须精确指向含导出interface的.go文件,不可为目录、通配符或_test.go文件;接口在internal包需显式指定-self_package;测试中必须defer ctrl.Finish()以触发EXPECT校验,且依赖须通过构造函数注入接口类型。

mockgen 命令必须精确指向含 interface 的 .go 文件
生成 mock 代码失败,常见原因是 mockgen -source 参数给了目录、通配符或 _test.go 文件。gomock 不扫描包,只读取单个源文件中的接口定义。
-
mockgen -source=external/payment.go✅ 正确:路径指向一个含PaymentGateway接口定义的普通.go文件 -
mockgen -source=external/❌ 报错:no interfaces found -
mockgen -source=external/*.go❌ 不识别通配符 -
mockgen -source=external/payment_test.go❌ 跳过测试文件,通常不含可导出接口
如果接口在 internal/api/service.go,需加 -self_package=yourmodule/internal/api,否则生成的 mock 会因包路径不一致导致 import 失败。
测试中漏掉 ctrl.Finish() = 白测
ctrl.Finish() 不是收尾仪式,而是验证触发器。没调它,所有 EXPECT() 都不会检查——方法没被调用、参数错、次数多或少,全被忽略,测试看似通过,实则无效。
- 必须写成
defer ctrl.Finish(),确保 panic 时也执行 - 不能放在
if分支里,也不能条件性跳过 - 若测试里用了多个 mock,共用一个
ctrl即可,不用每个都 new
典型错误:测试跑完没报错,但实际业务逻辑根本没触发依赖方法——就是因为少了这行。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
外包 SDK 没提供 interface?别硬套 gomock
很多外包 SDK(比如某支付厂商)只暴露结构体和方法,如 client.DoRequest(),没定义任何 interface。这时 mockgen 会报 undefined: NewMockXXX 或类型不匹配。
- 优先检查 SDK 文档或源码:是否已有
type PaymentClientInterface这类可导出接口?有就直接-source=xxx/sdk.go - 没有 interface?手写 fake 更快:
type FakePaymentClient struct { DoFunc func(req Req) (Resp, error) },实现DoRequest方法委托给DoFunc - 连 SDK 都没给,只有 HTTP 文档?跳过接口 mock,用
httptest.Server拦截请求并返回预设 JSON
强行用 gomock 去 mock 结构体方法,只会陷入类型转换错误和编译失败,浪费半天时间。
构造函数注入才是 mock 生效的前提
mock 对象传不进被测代码,根本原因是业务代码里直接 new 了依赖,比如 svc := &OrderService{sender: &SMTPSender{}}。这种写法让测试无法替换依赖,mock 再完整也没用。
- 把依赖作为参数传入构造函数:
func NewOrderService(sender EmailSender) *OrderService - 结构体字段必须是接口类型,不是具体 struct:
sender EmailSender,而非*SMTPSender - 测试时传
&MockEmailSender{},生产时传&SMTPSender{...}
接口抽象 + 构造注入这两步缺一不可。只做 mock 不改构造方式,等于在真机上贴一张假仪表盘——看着像在测,其实没连电路。

















