应使用 testify/assert 替代原生 if 判断,如 assert.equal(t, want, got) 一行完成断言并输出清晰差异;注意先求值再断言、用 jsoneq 校验 json、结合表驱动测试提升可维护性。

用 testify/assert 替代原生 if !t.Failed() 手动判断
Go 原生测试里写 if got != want { t.Errorf(...) } 会迅速让测试用例变得冗长、重复,且错误信息不直观。直接用 testify/assert 能把断言压缩成一行,失败时自动输出差异详情。
安装后直接导入:import "github.com/stretchr/testify/assert",然后在测试函数里用 assert.Equal(t, want, got) 即可。
-
assert.Equal对结构体、切片、map 都能深比较,比reflect.DeepEqual更友好(比如 nil slice 和空 slice 判为相等) - 所有
assert.Xxx函数返回bool,但默认不中断执行;想失败即停,改用require.Xxx(例如require.NoError(t, err)) - 注意:
assert不是标准库,CI 环境需确保go.mod已包含该依赖,否则go test会报找不到包
避免在断言中调用可能 panic 的函数
常见错误是把待测函数和断言写在同一行,比如 assert.Equal(t, 42, riskyFunc()) —— 如果 riskyFunc() panic,assert 根本没机会执行,测试直接崩溃,还看不到断言失败的上下文。
正确做法是先求值,再断言:
got := riskyFunc() assert.Equal(t, 42, got)
- 尤其对涉及 JSON 解析、数据库查询、HTTP 调用等易出错操作,必须拆开
- 如果确实需要链式调用(如
json.Marshal().([]byte)),用defer func(){...}()捕获 panic 并转为错误,再断言错误是否为 nil
用 assert.JSONEq 校验 API 返回体,别用 assert.Equal 直接比字符串
HTTP handler 测试中,常有人把响应 body 当字符串比对:assert.Equal(t, `{"id":1,"name":"foo"}`, string(body))。这极其脆弱:字段顺序一变、空格增减、float 小数位差异都会导致失败。
assert.JSONEq 会解析两边 JSON 后按语义比较,忽略格式与键序:
assert.JSONEq(t, `{"name":"foo","id":1}`, string(body))
- 它底层调用
json.Unmarshal,所以输入必须是合法 JSON;非法 JSON 会 panic,需提前校验 - 若响应含时间戳或随机 ID,先用正则或
strings.ReplaceAll预处理,再喂给JSONEq,别试图在 JSON 字符串里写模糊匹配
表驱动测试 + 断言组合,减少样板代码
多个输入/输出组合时,硬写一堆 TestXxx1/TestXxx2 很累。用切片定义测试用例,循环跑断言更干净:
tests := []struct {
name string
input string
want int
}{
{"empty", "", 0},
{"hello", "hello", 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := len(tt.input)
assert.Equal(t, tt.want, got)
})
}
- 每个
t.Run创建独立子测试,失败时能准确定位到name,而不是笼统报 “TestXXX failed” - 不要把断言逻辑封装进辅助函数——那样会让失败堆栈指向辅助函数而非测试用例本身,排查困难
- 若某个用例需特殊 setup/teardown,仍在对应子测试内处理,别提上去共用
断言简洁性的核心不是少敲几个字,而是让“预期”和“实际”在视觉上紧邻,且失败时能立刻看到差在哪。工具只是手段,关键在每条断言都只负责一件事,且不藏副作用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











