Go mod 好菜系列 - 0x0D testify 这口断言和 mock 很下饭
详细聊 testify 的 assert/require/mock 为什么这么高频、它适合替代哪些手写测试样板,以及怎么避免把测试写成断言堆砌。
如果说标准库里的 testing 已经足够你把测试写起来,那 testify 解决的,就是“写起来能不能更顺手一点”。它不是测试框架革命,但在真实 Go 项目里,出现频率真的高得很离谱。
testify 常见在哪几块
assertrequiremocksuite
真正最常见、最实用的,通常还是前两项:断言。mock 也很常见,但要看团队风格;suite 则更有争议一些。
为什么 assert / require 这么常见
因为标准库断言写起来确实偏朴素:
if got != want {
t.Fatalf("want %v, got %v", want, got)
}这当然没错,但条件一复杂、断言一多,测试函数会显得很碎。testify 把这一层劳动收得更顺手。
assert.Equal(t, want, got)
assert.NoError(t, err)assert 和 require 的区别别混了
assert:失败了会记错误,但继续往下跑require:失败了直接中断当前测试
这个区别在依赖链条明显的测试里特别重要。比如前面已经解析失败了,后面就别假装还能继续断言结构内容了。
resp, err := CallAPI()
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, 200, resp.Code)
assert.Equal(t, "ok", resp.Message)mock 为什么很多人又爱又怕
testify 的 mock 能帮你给接口打桩,这在 service 层测试里很常见。
type UserRepoMock struct {
mock.Mock
}
func (m *UserRepoMock) FindByID(id int64) (*User, error) {
args := m.Called(id)
if user, ok := args.Get(0).(*User); ok {
return user, args.Error(1)
}
return nil, args.Error(1)
}但 mock 也是一把双刃剑。它让测试更可控,但也很容易让测试只是在验证“你是不是按预期调用了 mock”,而不是在验证真正有价值的行为。
什么时候 testify 特别值
- 断言很多时
- 错误分支多时
- 需要快速写出可读测试时
- service 层需要 mock 协作者时
尤其是团队多人维护时,统一断言风格会明显降低阅读成本。
别把测试写成断言大杂烩
testify 的问题不在工具本身,而在于它很容易让人因为“断言写起来太方便”,就开始到处堆断言。测试不是断言数量竞赛,还是要围绕一个清晰目标来写。
小结
testify 这道菜很常吃,主要是因为它把测试里的很多小体力活做顺了:
assert和require提升可读性很明显mock能帮你隔离协作者,但别滥用- 它很适合做团队内统一测试风格的一层工具
- 工具只是辅助,测试目标本身还是要清楚
下一篇我们讲 swaggo。接口写多了以后,文档这件事如果全靠手工维护,很快就会变成一笔烂账。