教程前两步写得很扎实,但结尾断在 go tool cover -fu 了——顺手把覆盖率和基准测试这两块补完,再点几个真会踩的坑。

补全覆盖率那条命令:go tool cover -func=cover.out,按函数列出每行覆盖率,CI 里最好用它而不是看总百分比。跑全仓时如果测试分散,记得加 -coverpkg=./...,否则只统计被测试文件所在包的覆盖。另外覆盖率别当 KPI,-html 里重点看那些"覆盖了但没断言分支"的地方。

基准测试骨架:

func BenchmarkAdd(b *testing.B) {
    var sink int
    for i := 0; i < b.N; i++ {
        sink = Add(1, 2)
    }
    _ = sink // 防止编译器把整个循环优化掉
}

跑的时候用 go test -bench=. -benchmem -run=^$,-run=^$ 是为了跳过普通单测只跑基准;-benchmem 给出每次分配次数和字节数。基准里有耗时初始化(读文件、建连接)就调 b.ResetTimer(),否则数字全被污染。想要更稳的对比用 -benchtime=3s -count=5 配合 benchstat。

几个容易栽的点:一是 t.Run 的名字里带空格会被转成下划线,-run TestAdd/正数_加法 才对得上,别照着肉眼写的名字敲;二是子测试开 t.Parallel() 时,Go 1.22 之前 c := c 更是必须的,而且并行后输出顺序不再固定;三是辅助函数里第一行写 t.Helper(),不然报错行号全指向辅助函数,排查时很痛苦;四是 TestMain(m *testing.M) 适合做 DB 迁移这类全局 setup,但别忘了 os.Exit(m.Run())。

延伸一句:-short 模式配合 testing.Short() 跳过慢测试,本地开发体验会好很多,这类约定最好在项目 README 里写死。