Go 单元/模糊/基准测试

Go 测试体系总览

Go 在标准库 testing 包中提供了三种互补的测试能力:单元测试验证正确性、基准测试评估性能、模糊测试(Go 1.18+)用随机输入发现边缘 bug。

1. 单元测试(Unit Test)

约定:文件名以 _test.go 结尾,函数名 Test 开头,参数 *testing.T

func TestAdd(t *testing.T) {
    if add(1, 2) != 3 {
        t.Error("1 + 2 should be 3")
    }
}

工程上推荐表格驱动测试(Table-Driven Tests),一组用例一张表,覆盖边界一目了然:

func TestAdd(t *testing.T) {
    cases := []struct {
        name string
        a, b int
        want int
    }{
        {"positive", 1, 2, 3},
        {"zero", 0, 0, 0},
        {"negative", -1, -2, -3},
    }
    for _, c := range cases {
        t.Run(c.name, func(t *testing.T) {
            if got := add(c.a, c.b); got != c.want {
                t.Errorf("add(%d,%d) = %d, want %d", c.a, c.b, got, c.want)
            }
        })
    }
}
go test -v ./...     # 全部测试,显示详情
go test -run TestAdd # 只跑某个测试
go test -cover       # 输出覆盖率

2. 基准测试(Benchmark)

函数名 Benchmark 开头,参数 *testing.B,被测代码必须放在 b.N 循环里(框架自动调整 N 直到测量稳定):

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        add(1, 2)
    }
}

// 并行基准
func BenchmarkParallel(b *testing.B) {
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            add(1, 2)
        }
    })
}
go test -bench . -benchmem        # 时间 + 内存分配
go test -bench . -benchtime=2s    # 指定单次时长
go test -bench . -cpu=1,4         # 对比不同核数

看结果时重点盯两列:ns/op(单次耗时)和 B/op(每次分配字节数)、allocs/op(分配次数)——内存分配往往是性能瓶颈。

3. 模糊测试(Fuzz)

函数名 Fuzz 开头,参数 *testing.F,先用 f.Add 提供种子语料,再写模糊目标:

func FuzzReverse(f *testing.F) {
    f.Add("hello")                  // 种子
    f.Add([]byte{0xff, 0x00})
    f.Fuzz(func(t *testing.T, s []byte) {
        got := reverse(s)
        if !reflect.DeepEqual(reverse(got), s) {
            t.Fatalf("reverse(reverse(%v)) != %v", s, s)
        }
    })
}
go test -fuzz FuzzReverse -fuzztime=10s

模糊测试自动生成输入、尝试让代码崩溃或违反断言,并在崩溃时自动最小化出最小复现用例。特别适合解析器、编解码、格式处理这类”输入空间大”的函数。

对比总结

类型目的前缀参数关键命令
单元测试验证逻辑Test*testing.T-run / -cover
基准测试评估性能Benchmark*testing.B-bench / -benchmem
模糊测试发现边界 bugFuzz*testing.F-fuzz / -fuzztime

最佳实践

  • 单元测试覆盖分支与边界(空输入、nil、极值、超时);
  • 基准测试关注 ns/op 与内存分配,优化高频调用路径;
  • 模糊测试瞄准”输入复杂”的函数(解析器、编解码器);
  • CI 里跑 go test -race ./... + -cover,把回归挡在上线前。
滚动至顶部