golang test
1. Go 测试基础概念
Go 的测试系统内置在 go test 命令中,支持三种主要类型:
- 单元测试(Unit Tests):函数名以
Test开头 - 示例测试(Example Tests):函数名以
Example开头 - 基准测试(Benchmarks):函数名以
Benchmark开头 - 模糊测试(Fuzz Tests):函数名以
Fuzz开头(Go 1.18+)
所有测试文件必须以 _test.go 结尾,放在与被测代码相同的包中。
2. 单元测试(Unit Tests)
编写规则
func TestXxx(t *testing.T) {
// 测试逻辑
if got := Foo(); got != want {
t.Errorf("Foo() = %v, want %v", got, want)
}
// 或者使用 t.Fatalf 直接失败退出
}常用方法
t.Error/t.Errorf:记录错误,继续执行t.Fatal/t.Fatalf:记录错误,立即停止当前测试t.Log/t.Logf:打印日志(只有测试失败或用 -v 时才显示)t.Helper():标记辅助函数,在错误时不显示该函数的行号- 子测试(Subtests)与表驱动测试(Go 1.7+)
表驱动测试(推荐方式)
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"正数", 2, 3, 5},
{"负数", -1, 1, 0},
{"零", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
}
})
}
}运行单元测试
go test # 运行当前包所有测试
go test ./... # 递归运行所有子包测试
go test -v # 显示详细输出(包括 t.Log)
go test -run TestAdd # 只运行名字匹配 TestAdd 的测试
go test -run TestAdd/negative # 只运行子测试 'negative'
go test -count=1 # 禁用测试缓存(每次都重新运行)
go test -short # 跳过标记为长耗时的测试(配合 if testing.Short())3. 示例测试(Example Tests)
作用
- 作为文档示例(会出现在 godoc 中)
- 同时作为可执行测试
编写方式
func ExampleAdd() {
fmt.Println(Add(2, 3))
// Output: 5
}- 注释
// Output:后面的内容必须与实际输出完全一致(包括换行) - 可以有多个 Output 行,支持正则匹配(用 // Unordered output:)
运行:go test -run Example 或直接查看文档。
4. 基准测试(Benchmarks)
编写基准函数
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ { // b.N 由测试框架自动调整
Add(2, 3)
}
}表驱动基准测试(推荐)
func BenchmarkAdd(b *testing.B) {
tests := []struct {
name string
a, b int
}{
{"small", 1, 2},
{"large", 1000000, 2000000},
}
for _, tt := range tests {
b.Run(tt.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(tt.a, tt.b)
}
})
}
}常用运行命令
go test -bench=. # 运行所有基准测试
go test -bench=BenchmarkAdd # 只运行特定基准
go test -bench=. -benchmem # 显示内存分配统计(B/op 和 allocs/op)
go test -bench=. -count=10 # 运行 10 次取平均(减少波动)
go test -bench=. -benchtime=5s # 每个基准至少运行 5 秒(更准确)
go test -bench=. -cpu=1,4,8 # 测试不同 GOMAXPROCS 下的性能
go test -run=^$ -bench=. # 跳过单元测试,只跑基准(重要!)输出解释
BenchmarkAdd-8 100000000 10.5 ns/op 0 B/op 0 allocs/op-8:GOMAXPROCS=8100000000:循环执行了 1 亿次10.5 ns/op:平均每次操作 10.5 纳秒0 B/op和0 allocs/op:每次操作分配的内存和次数(需加 -benchmem)
高级技巧
- 重置定时器:
b.ResetTimer()(排除初始化时间) - 停止/启动定时器:
b.StopTimer()/b.StartTimer() - 避免编译器优化:使用
result := Add(x, y)并防止 result 被优化掉(可赋给全局变量或用runtime.KeepAlive(result))
func BenchmarkFib(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
Fib(10)
}
}5. 模糊测试(Fuzz Testing,Go 1.18+)
编写方式
func FuzzReverse(f *testing.F) {
f.Add("hello") // 种子语料
f.Fuzz(func(t *testing.T, s string) {
rev := Reverse(s)
double := Reverse(rev)
if double != s {
t.Errorf("Reverse twice: %q != %q", double, s)
}
})
}运行
go test -fuzz=FuzzReverse # 运行指定模糊测试
go test -fuzz=. -fuzztime=30s # 运行所有模糊测试 30 秒6. 测试覆盖率
go test -cover # 显示覆盖率百分比
go test -coverprofile=cover.out # 生成覆盖率文件
go test -covermode=atomic # 更精确的并发覆盖统计
go tool cover -html=cover.out # 生成 HTML 可视化报告7. 常用最佳实践总结
- 所有测试文件放在被测包同目录,文件名
_test.go - 优先使用表驱动测试
- 基准测试一定要加
-run=^$避免运行单元测试干扰 - 重要性能代码必须加
-benchmem观察内存分配 - 使用
-count=5~10多跑几次减少测量误差 - 关键路径用基准测试持续监控性能回归
- 覆盖率目标一般 ≥80%,关键包争取 100%


