go测试需满足四个硬性条件:测试文件名以_test.go结尾、函数名以test开头、签名含*testing.t参数、与被测代码同包;表驱动测试须显式命名场景、覆盖非法输入、避免闭包陷阱;压力测试需用hey等专用工具而非-bench;覆盖率高不等于质量高,必须显式验证错误路径。

go test 不是万能的,它只跑单元测试;压力测试得另起炉灶,别指望 go test -bench=. 模拟真实并发。
go test 执行不了?先查这四个硬性条件
很多同学执行 go test 后提示 no test files 或者 undefined: XXX,根本不是代码写错了,而是没满足 Go 测试的底层约定:
- 测试文件名必须以
_test.go结尾(user_test.go✅,test_user.go❌) - 测试函数名必须以大写
Test开头(TestLogin✅,testLogin❌) - 函数签名必须是
func TestXxx(t *testing.T)(不能是*testing.B,那是基准测试用的) - 测试文件和被测代码必须在同一个包下(除非你刻意用了
xxx_test包做黑盒测试,但业务代码里基本不用)
常见陷阱:Add 函数首字母小写 → 同包内可调用,但测试文件若放在独立 xxx_test 包里就报 undefined;go test ./... -run=TestXxx 却没反应 → 先确认当前目录是不是模块根目录,go test 默认只扫当前包。
表驱动测试写法不对,覆盖率再高也白搭
用切片定义多个 case 看似覆盖全了,但容易漏掉真正会崩的点。关键不在数量,而在结构是否暴露风险:
-
name字段要直说场景,比如"returns_error_on_empty_email",而不是"case1" - 每个 case 的输入和预期必须显式写出,别在循环里算
expected := tc.a + tc.b,失败时看不出哪组数据出问题 - 必须包含非法输入:空字符串、
nil、负数 ID、超长字段——这些才是线上 panic 的主力 - 闭包陷阱:用
t.Run时,循环变量tc会被捕获,所有子测试实际跑的都是最后一组数据;得加一行tc := tc显式复制
复杂返回值别直接 == 比 struct,reflect.DeepEqual 容易掩盖字段差异;更稳妥的是只验关键字段,比如 err == nil 和 user.ID > 0。
压力测试 ≠ go test -bench,别拿它压接口
go test -bench=. 是基准测试(benchmark),它测的是单 goroutine 下函数的吞吐和分配,不建连接、不发 HTTP、不模拟用户行为。真要压 API 接口,得用专门工具:
- 本地快速验证可用
go-wrk或hey,比如hey -n 1000 -c 50 http://localhost:8080/api/user - 关注指标不是 QPS 多高,而是
goroutine是否持续增长(泄露)、HTTP 连接有没有复用(http.DefaultClient要配Transport)、下游服务响应是否拖慢整体链路 - 压测脚本自己写也行,但记得用
sync.WaitGroup控制并发,别直接起 1000 个 goroutine 然后不管——本地内存瞬间飙到 6GB+ 是常态
一个常被忽略的事实:go test -benchmem 只告诉你内存分配次数和大小,它不反映 GC 压力;真要看堆增长,得结合 pprof 抓 /debug/pprof/heap。
覆盖率数字高 ≠ 代码稳,重点盯住错误路径
go test -coverprofile=c.out && go tool cover -html=c.out 能生成可视化报告,但 95% 覆盖率可能全是 happy path。线上崩得最狠的,往往是 if err != nil 分支里那几行没测过的逻辑:
- 网络超时、数据库连接中断、第三方 API 返回 503——这些错误流必须有对应测试 case
- 不要只测
err == nil,要测errors.Is(err, context.DeadlineExceeded)这类具体类型 - mock 外部依赖时,别只 mock 成功路径;用
gomock或 hand-rolled interface 实现时,一定要提供失败变体
真正的质量卡点不在“有没有测”,而在“有没有逼它错”。每次改完代码,先问一句:这个改动会让哪条错误路径提前触发?然后补上那个 case。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











