golang t *testing.T、b *testing.B、m *testing.M、pb *testing.PB、f *testing.F 等的区别
t *testing.T、b *testing.B、m *testing.M、pb *testing.PB、f *testing.F 等是 Go testing 包中不同的测试上下文类型,它们各自用于不同的测试场景,拥有不同的方法和行为。
单元测试规范
测试函数必须放在 _test.go 结尾的文件中,方法名必须Test开头,紧接着大写开头的函数名称 普通测试,方法名应该是 TestXxx(t *testing.T),其中 Xxx 可以是任意名称(不能是 Main)
简单来说:它们都是”测试函数的参数”,但类型不同,决定了这个测试函数是做什么类型的测试。
一、核心类型概览
类型 常用别名 用途 函数命名规则 执行命令 *testing.T t 单元测试、功能测试 TestXxx go test *testing.B b 基准测试、性能测试 BenchmarkXxx go test -bench *testing.M m 测试主控、全局初始化/清理 TestMain go test *testing.PB pb 并行测试控制(在子测试中) 配合 b.RunParallel go test -bench *testing.F f 模糊测试、随机输入生成 FuzzXxx go test -fuzz
二、详细对比与示例
1. *testing.T – 单元测试(最常用)
用途:验证代码逻辑是否正确
关键方法:
t.Log():输出日志 t.Error():标记失败,继续执行 t.Fatal():标记失败,立即终止 t.Skip():跳过测试 t.Parallel():并行执行
go
func TestAdd(t *testing.T) {
t.Log("开始测试") // 普通日志
if 1+1 != 2 {
t.Error("加法失败") // 记录错误但不停止
}
if 2+2 != 4 {
t.Fatal("致命错误") // 立即停止当前测试
}
t.Skip("跳过剩余测试") // 跳过后续代码
}
2. *testing.B – 基准测试(性能测试)
用途:测量代码执行时间、内存分配
关键特性:
b.N:自动调整的循环次数(框架会找到稳定值) b.ResetTimer():重置计时器 b.StopTimer() / b.StartTimer():暂停/恢复计时 b.ReportAllocs():报告内存分配统计 b.RunParallel():并行性能测试
go
func BenchmarkAdd(b *testing.B) {
// 性能测试前的准备工作
b.ResetTimer() // 重置计时器,忽略准备时间
// b.N 由测试框架自动决定
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)
}
})
}
输出示例:
text BenchmarkAdd-8 1000000000 0.25 ns/op 0 B/op 0 allocs/op -8:8个CPU核心 1000000000:执行次数(b.N) 0.25 ns/op:每次操作耗时 0 B/op:每次操作内存分配 0 allocs/op:每次操作分配次数
3. *testing.M - 测试主控(全局控制)
用途:在整个测试套件运行前后进行全局初始化和清理
关键方法:
m.Run():运行所有测试,返回退出码
go
func TestMain(m *testing.M) {
// 全局初始化(连接数据库、加载配置等)
fmt.Println("所有测试开始前执行")
// 运行所有测试
code := m.Run()
// 全局清理(关闭连接、删除临时文件等)
fmt.Println("所有测试结束后执行")
// 退出(必须)
os.Exit(code)
}
func TestA(t *testing.T) {
fmt.Println("测试A")
}
func TestB(t *testing.T) {
fmt.Println("测试B")
}
输出:
text 所有测试开始前执行 测试A 测试B 所有测试结束后执行
4. *testing.PB - 并行测试控制
用途:在基准测试的并行模式下控制迭代
出现场景:仅在 b.RunParallel() 的回调函数中作为参数
关键方法:
pb.Next():返回是否还有下一次迭代
go
func BenchmarkParallelAdd(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() { // 循环直到没有更多工作
Add(1, 2)
}
})
}
5. *testing.F - 模糊测试(Go 1.18+)
用途:通过随机生成的输入来发现边界情况、崩溃和逻辑错误
关键方法:
f.Add():添加种子数据 f.Fuzz():定义模糊测试函数
go
func FuzzAdd(f *testing.F) {
// 添加种子数据(正常值、边界值、异常值)
f.Add(1, 2) // 正数
f.Add(-1, 1) // 负数
f.Add(0, 0) // 零
f.Add(1000000, 2000000) // 大数
// 模糊测试目标
f.Fuzz(func(t *testing.T, a, b int) {
result := Add(a, b)
// 验证性质:加法交换律
if Add(a, b) != Add(b, a) {
t.Errorf("交换律失败: %d+%d != %d+%d", a, b, b, a)
}
// 验证性质:加法结合律
if Add(Add(a, b), c) != Add(a, Add(b, c)) {
t.Errorf("结合律失败")
}
})
}
运行命令:
go test -fuzz=FuzzAdd -fuzztime=30s
三、快速对比表
特性 *testing.T *testing.B *testing.M *testing.PB *testing.F 主要用途 功能正确性 性能测量 全局控制 并行迭代 随机测试 运行次数 1次 N次(自动调整) 1次 N次(并行) 多次(随机) 是否自动循环 否 是(通过b.N) 否 是(通过pb.Next) 是(自动生成) 可并行执行 是(t.Parallel) 是(RunParallel) 否 是 是(多进程) 常见方法 Log/Error/Fatal ResetTimer/StopTimer Run Next Add/Fuzz Go版本要求 1.0+ 1.0+ 1.0+ 1.0+ 1.18+
四、实际应用场景
场景1:测试一个HTTP处理函数
func TestHandler(t *testing.T) {
req := httptest.NewRequest("GET", "/api/user", nil)
w := httptest.NewRecorder()
handler(w, req)
if w.Code != http.StatusOK {
t.Errorf("期望200,得到%d", w.Code)
}
}
场景2:性能对比两种排序算法
func BenchmarkQuickSort(b *testing.B) {
data := generateRandomSlice(1000)
for i := 0; i < b.N; i++ {
quickSort(data)
}
}
func BenchmarkBubbleSort(b *testing.B) {
data := generateRandomSlice(1000)
for i := 0; i < b.N; i++ {
bubbleSort(data)
}
}
场景3:所有测试前连接数据库
var db *sql.DB
func TestMain(m *testing.M) {
// 初始化
var err error
db, err = sql.Open("mysql", "user:pass@/dbname")
if err != nil {
fmt.Println("数据库连接失败")
os.Exit(1)
}
// 运行测试
code := m.Run()
// 清理
db.Close()
os.Exit(code)
}
场景4:测试字符串解析的边界情况
func FuzzParseInt(f *testing.F) {
seeds := []string{"0", "123", "-456", "9999999999", "abc"}
for _, s := range seeds {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
result, err := strconv.Atoi(s)
if err == nil {
// 如果解析成功,结果应该是数字
_ = result
}
})
}
五、关键区别总结
*testing.T:功能测试,验证"做得对不对" *testing.B:性能测试,测量"做得快不快" *testing.M:全局控制,在"所有测试前后"做事 *testing.PB:并行控制,配合基准测试的"并发迭代" *testing.F:模糊测试,让"计算机帮你找Bug"
记忆技巧:
T = Test(测试) B = Benchmark(基准) M = Main(主控) PB = Parallel Benchmark(并行基准) F = Fuzz(模糊)

