Go 中 mock 依赖接口,mockgen 需导出接口、正确路径和命名;手写 mock 更快适用于简单接口或无 interface 的 SDK;httptest.Server 仅限单元测试内网验证;EXPECT 必须配 Times() 和 ctrl.Finish() 才有效。

Go 里没有“Mock 框架”这种东西——你没法像 Java 那样 mock 任意结构体或类,所有可用的 mock 方案都严格依赖接口(interface{})和编译期替换。没定义接口,就根本走不通。
为什么 mockgen 生成失败或报 undefined 错误
这不是工具装错了,而是你试图 mock 的目标根本不是接口,或者接口没导出。
-
mockgen -source=xxx.go必须指向一个含 导出接口定义 的 .go 文件,不能是目录、不能是_test.go、不能是 internal 包下未显式声明包路径的文件 - 接口名和方法名必须首字母大写(如
UserRepository,不是userRepository),否则mockgen找不到或生成空文件 - 如果接口在
internal/api/下,要加-self_package=yourmodule/internal/api,否则生成的 mock 无法被正确 import - 常见错误
cannot use mockX as type ExternalService:说明业务代码里直接用了 SDK 的 struct(比如*sdk.Client),而不是它暴露的 interface;得先抽一层 interface,再 mock
手写 mock 比 gomock 更快的三种情况
别一上来就跑 mockgen,很多场景手写两行 struct 更省事、更可控。
- 接口只有 1–2 个方法,且参数/返回值简单(如
Get(id int) (*User, error)) - 外包 SDK 没提供 interface,只给了 struct 和文档——这时写
FakePaymentClient比硬套mockgen更快 - 需要动态行为验证,比如根据输入参数返回不同 error 或 panic,
DoAndReturn()虽好但手写GetUserFunc func(int) (*User, error)字段更直观
示例:type MockUserRepo struct { GetUserFunc func(int) (*User, error) },然后实现 GetUser 方法直接调用该字段。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
httptest.Server 不是 mock 工具,是测试辅助器
它只适用于单元测试内网请求验证,**不能用于前端联调、Postman 测试或跨进程访问**。
-
httptest.NewServer返回随机端口(如http://127.0.0.1:56789),前端无法稳定引用 - 它不处理 CORS、不支持长连接、不设
Content-Type头,默认响应体也没 charset,fetch 会解析失败 - 生命周期绑定单个 test 函数,
defer server.Close()漏掉就会端口泄漏,多次运行测试直接卡住 - 真要做离线联调,用
net/http起独立服务:监听:8080、手动设Access-Control-Allow-Origin、精确匹配路径和 method、用w.WriteHeader()控制状态码
EXPECT() 不写 Times() 就等于没测
ctrl.Finish() 是开关,EXPECT() 是契约——漏掉 Times() 或不调 ctrl.Finish(),测试永远“成功”,但实际可能完全没调用目标方法,或调错次数、错顺序、错参数。
- 必须写
defer ctrl.Finish(),确保 panic 时也触发校验 - 幂等操作要显式写
.Times(0)或.Times(3),不能靠默认的Times(1) - 慎用
gomock.Any():涉及分支判断的参数(如status、code)必须用具体值或自定义 matcher,否则if req.Status == "failed"这条路永远跑不到 - 覆盖率报告里看不到的坑:未注册的调用(unexpected call)默认被忽略,得开
gomock.CallTracker模式才能捕获
最常被跳过的其实是「错误路径」的 EXPECT:比如 GetUser(0).Return(nil, errors.New("invalid id")) 这一行,往往比正常路径还关键。

















