go单元测试需严格遵循约定:函数名以test开头且唯一参数为*testing.t,测试文件名以_test.go结尾且与被测代码同包;误用t.fatal会提前终止测试,-v可显示详细执行过程。

Go 单元测试不是“加个 _test.go 就完事”,它有一套轻但硬的约定——不满足,go test 直接静默跳过,连报错都没有。
TestXxx 函数名和 *testing.T 参数缺一不可
常见错误是写成 func testAdd()(小写开头)、func TestAdd()(没参数)、或 func TestAdd(t testing.T)(漏了星号)。这三种写法 go test 全部无视,不会运行也不会提示。
- 函数名必须以大写
Test开头,后接驼峰或下划线分隔的大写字母(如TestUserLogin、Test_user_save) - 唯一参数必须是
*testing.T,不能是testing.T或any - 测试文件必须与被测代码同包,且文件名以
_test.go结尾(如user.go对应user_test.go)
用 t.Error 还是 t.Fatal?关键看是否要继续执行
这不是“严重程度”问题,而是控制流问题。误用 t.Fatal 会导致测试提前退出,掩盖后续问题。
- 验证多个断言(比如检查返回值、状态码、日志输出)→ 用
t.Error或t.Errorf,失败后继续跑完所有检查 - 前置条件失败(如 mock DB 初始化失败、配置加载出错)→ 用
t.Fatal快速终止,避免后续无意义执行 -
t.Fatal不会自动 return,后面如果还有代码,得手动加return,否则可能 panic 或逻辑错乱
为什么 go test 没输出?默认只报失败和显式日志
全量通过时,go test 默认只打印 ok 0.001s。这不是卡住,是设计如此。想看每条测试的执行过程,必须加 -v。
- 加
-v:显示每个TestXxx的开始、结束和t.Log输出 - 加
-run="TestUser":只运行匹配的测试函数,支持正则(如-run="^TestUser.*$") - 加
-cover:查看测试覆盖率;-coverprofile=coverage.out可导出供可视化分析
依赖外部服务时,必须解耦并可控注入
直接在 TestXxx 里调 http.Get、连真实 Redis 或读系统时间,会让测试变慢、不稳定、不可重复。
- 把依赖抽象为接口(如
type Cache interface { Get(key string) ([]byte, error) }),测试时传入内存实现 - 时间相关逻辑不要直接调
time.Now(),改为接收func() time.Time参数或通过接口注入时钟 - HTTP handler 测试别起 server,用
httptest.NewRequest+httptest.NewRecorder构造请求/响应上下文
最容易被忽略的是:测试文件和被测代码不在同一包、函数签名少一个星号、或者把测试逻辑塞进 main 函数——这些都不会报错,只会让 go test 彻底无视你写的“测试”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











