Mockery不是必须的,但它是解决跨包接口模拟最省力的方案;真正需优先做的是将依赖抽象为小接口并用结构体字段注入,否则生成再多MockXxx也无法测清逻辑。

Mockery 不是必须的,但它是解决跨包接口模拟最省力的方案;真正需要优先做的,是把依赖抽象成小接口、用结构体字段注入——否则生成再多 MockXxx 也没法测清楚逻辑。
为什么先写接口再考虑 Mockery
Go 的 mock 能力不来自工具,而来自接口隐式实现机制。如果你的业务代码直接依赖 *sql.DB 或 http.Client,Mockery 生成的 mock 就没法替换进去——它只认接口类型。
- 定义接口时只保留被测逻辑真正用到的方法,比如
UserRepository只要GetByID和Save,别把事务、连接池方法全塞进去 - 接口声明放在被调用方(如 usecase 层),而不是实现方(如 repository 层),避免循环依赖
- 确保接口在同一个 module 内可被引用,否则
mockery --name=XXX找不到符号
跨包生成 mock 时 mockery init 配置关键点
跨包模拟失败,90% 是因为 .mockery.yml 没配对路径或没开递归。默认配置不会自动处理子包里的接口。
-
packages下写的路径必须和go list输出一致,比如github.com/your-org/project/internal/service,不能简写成internal/service -
recursive: true必须显式开启,否则子目录如internal/service/auth里的接口不会被扫描 -
dir: mocks/{{.PackagePath}}比mocks/更安全,能避免不同包同名接口覆盖生成文件 - 如果接口用了泛型,确认你用的是
mockery/v3,v2不支持泛型接口生成
生成后 mock 的使用陷阱
生成的 MockXxx 结构体本身不带行为,所有返回值、调用验证都要手动设——这点新手常忽略,结果测试跑过但实际没验证逻辑。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 用
mock.On("MethodName", arg1, arg2).Return(ret1, ret2)才算注册了期望,光 new 出来没用 - 如果方法有
context.Context参数,别传nil,用context.Background()或testContext,否则On()匹配失败 - 启用
with-expecter: true后,要用mock.EXPECT().Method(...).Return(...),它会自动校验调用次数,比On更严格 - 测试结束前记得调用
mock.AssertExpectations(t),否则即使调用没发生也不会报错
什么时候该放弃 Mockery 改用手写 fake
Mockery 适合中大型项目里稳定、复用率高的接口;但以下情况手写 fake 更快、更可控:
- 接口只有 1–2 个方法,比如
type Clock interface { Now() time.Time } - 需要在 mock 里嵌入
sync.Mutex或计数器做并发测试 - 测试要覆盖多个错误分支,而
On().Return()写起来比结构体字段控制还啰嗦 - 接口定义在第三方 module(如
cloud.google.com/go/storage),Mockery 无法访问源码时,只能靠gomock或手写适配层
真正难的不是生成 mock,而是判断哪些依赖值得隔离、哪些该直接集成测试——比如 HTTP 调用优先用 httptest.Server,而不是 mock 客户端。


















