手写 fake 更快更稳更少出错,尤其适用于自定义内部接口;mockgen 仅适用于外部 SDK 或需严格校验调用顺序的场景。

手写 fake 比用 mockgen 更快、更稳、更少出错——尤其当你 mock 的是自己定义的接口(比如 UserRepository、Notifier)时。
什么时候该跳过 mockgen 直接手写 fake
绝大多数内部接口,手写 fake 是更合理的选择。它不引入额外工具链、不生成冗余代码、不依赖黑盒验证逻辑。
- 接口方法 ≤ 5 个,且全在你项目里定义:手写
MockUserRepository几行就完事,mockgen却会塞一堆EXPECT/Call/Finish框架代码 - 接口变更后忘记重跑
mockgen→ 编译失败或运行时 panic,而手写 fake 编译器直接报错,问题暴露得早 - 测试只调用
GetUser,却被迫为DeleteUser写EXPECT()→ 手写 fake 完全按需实现,无此负担 - 需要并发安全读写状态(如记录调用次数、最后传入参数):嵌入
sync.Mutex+ 导出字段(Called bool、LastID int),测试里直接assert.True(t, mock.Called)
HTTP 客户端 Mock 必须抽离,不能硬编码 http.DefaultClient
硬编码 http.Get 或 new(http.Client) 是 CI 上随机超时、404、TLS 握手失败的根源。这不是网络问题,是测试设计缺陷。
- 把客户端抽成结构体字段,类型设为
HTTPDoer(自定义接口)或*http.Client,并在构造函数中注入 - 测试中用
httptest.NewServer启动本地 handler,把server.URL注入被测 client - handler 返回 JSON 时务必用
json.NewEncoder(w).Encode(resp),避免缺失Content-Type: application/json导致反序列化失败
外部 SDK 接口才值得用 gomock + mockgen
只有两类场景值得引入 gomock 工具链:mock 外部模块接口,或业务逻辑严格依赖调用顺序和参数匹配。
立即学习“go语言免费学习笔记(深入)”;
- 你要 mock 的是
cloud.google.com/go/storage.Client或github.com/aws/aws-sdk-go-v2/service/s3.S3Client这类外部 SDK:它们没提供可替换接口,方法多、签名复杂,手写 fake 成本高 - 业务逻辑是状态机驱动(如支付流程),必须校验调用顺序、参数值、调用次数:这时才需要
After()、AnyTimes()、DoAndReturn()等精细控制 - 必须配对使用
gomock.Controller:ctrl := gomock.NewController(t)+defer ctrl.Finish(),否则未满足的EXPECT会被静默忽略,测试看似通过实则失效
真正容易被忽略的是:fake 结构体字段是否导出、是否带锁、是否能被测试直接断言——这些细节决定了你能不能在 10 行内写出一个可靠、可读、可维护的 mock 实现,而不是靠框架生成一堆看不懂的模板代码。


















