gomock生成mock前必须有可导出interface,否则mockgen无法工作;常见错误源于未抽象外包SDK为interface,应优先使用SDK提供的interface或手写Fake,而非硬套mockgen。

gomock 生成 mock 前必须有可导出的 interface
没有 interface,mockgen 就是无米之炊。常见错误如 undefined: NewMockExternalService 或 cannot use mockX as type ExternalService,根本原因不是工具没装对,而是业务代码直接调用了外包 SDK 的结构体(比如 client.DoRequest()),没经过 interface 抽象。
检查你的依赖是否已封装成 interface:如果外包 SDK 自带 type PaymentService interface { Charge(...) },就直接用它;如果没有,别硬套 mockgen,手写 FakePaymentClient 更快、更可控。
-
mockgen -source=external/payment.go必须指向一个含interface定义的 .go 文件,不能是目录、*.go、_test.go - 若 interface 在
internal/下,加-self_package=yourmodule/internal/payment显式声明 - 生成后打开
mocks/mock_payment.go,确认有NewMockPaymentClient(ctrl *gomock.Controller)—— 没有说明路径或包名不匹配
测试里漏掉 ctrl.Finish() = 白测
ctrl.Finish() 不是仪式感收尾,它是 gomock 的验证开关。漏掉它,所有 EXPECT() 都不会触发校验:方法没被调用、参数错、调用次数超限、顺序不对……全被忽略,测试“绿了”但毫无意义。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 必须写在
defer里:defer ctrl.Finish(),保证 panic 时也执行 - 每个测试函数都要有自己的
ctrl := gomock.NewController(t),不要复用 - 不写
.Times(1)默认只允许调用一次;允许多次用.AnyTimes()或.Times(0, 1)
参数匹配别传字面量,用 gomock.Eq() 和 gomock.Any()
直接写 mockCli.EXPECT().Charge("order-123", ...) 会报类型不匹配错误,因为 gomock 要求参数匹配器(matcher)类型一致。它不接受原始值,只接受实现了 gomock.Matcher 接口的值。
立即学习“go语言免费学习笔记(深入)”;
- 精确匹配用
gomock.Eq("order-123"),不是"order-123" - 忽略某参数用
gomock.Any(),不是nil或空结构体 - 匹配结构体字段可用
gomock.AssignableToTypeOf(&MyReq{}),但慎用——易掩盖字段变更 - HTTP 客户端这类外部依赖,优先用
httptest.Server模拟整条请求链,而不是 mock client 方法
mock 是给接口用的,不是给框架或 SDK 结构体用的
Go 没有“框架级 mock 模块”。所谓“契约驱动”,契约指的是你定义的 interface,不是 Swagger 文档、不是 HTTP 路径、更不是第三方 SDK 的 struct。如果你的代码里还存在 import "xxx/sdk" 然后直接 new 一个 client 调方法,那 mockgen 再熟也没用 —— 你根本没把依赖抽象出来。
- 真实调用链应是:
UserService → PaymentService interface → (real impl or mock impl) - 外包只给 HTTP 文档?跳过 interface mock,直接起
httptest.Server返回 JSON + 状态码 - mock 文件
package名必须和destination所在目录名一致,否则import报no required module provides package
mockgen 命令怎么写,而是 interface 是否干净、是否只描述行为、是否被业务代码真正依赖 —— 其他都是表象。


















