单元测试
2026年9月6日
标准库自带 testing 和 go test。测试文件和源码放同一包,名字以 _test.go 结尾。测试函数以 Test 开头,签名是 func TestXxx(t *testing.T)。
单元测试
calc.go:
package calc
func Add(a, b int) int { return a + b }
go
calc_test.go:
package calc
import "testing"
func TestAdd(t *testing.T) {
got := Add(1, 2)
if got != 3 {
t.Fatalf("Add(1,2)=%d, want 3", got)
}
}
go
命令:
go test
go test -v # 每个用例的结果
go test -run TestAdd
go test -count=1 # 关掉结果缓存
bash
常用日志:
| 方法 | 作用 |
|---|---|
t.Log / t.Logf | 失败或 -v 时才看见 |
t.Error / t.Errorf | 记失败,继续跑这个函数 |
t.Fatal / t.Fatalf | 记失败并立刻结束这个测试函数 |
t.Skip | 跳过 |
编辑器里函数左边的绿色三角,等价于 go test -run 那一个。
性能测试是 BenchmarkXxx(b *testing.B),用 go test -bench=.。
子测试
同一函数多组输入,用 t.Run。子测试里的 Fatal 只结束这一组,不会停掉整个 TestXxx。
func TestAdd(t *testing.T) {
t.Run("pos", func(t *testing.T) {
if Add(1, 2) != 3 {
t.Fatal(Add(1, 2))
}
})
t.Run("neg", func(t *testing.T) {
if Add(-1, -2) != -3 {
t.Fatal(Add(-1, -2))
}
})
}
go
用例多了就做成表:
cases := []struct {
name string
a, b, want int
}{
{"pos", 1, 2, 3},
{"neg", -1, -2, -3},
{"zero", 0, 0, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := Add(c.a, c.b); got != c.want {
t.Fatalf("got %d want %d", got, c.want)
}
})
}
go
go test -run TestAdd/pos 只跑其中一个。
TestMain 函数
一个包可以有一个 TestMain,当作测试进程的入口,做准备和收尾:
func TestMain(m *testing.M) {
// 建临时库、改环境变量……
code := m.Run()
// 清理
os.Exit(code)
}
go
一定要调用 m.Run(),并且用它的返回码 os.Exit。漏了 m.Run(),所有测试都不会跑。