Go测试由go test和testing包原生支持,需严格遵循_test.go命名、同包存放、TestXxx函数定义等规则;慎用t.Parallel()避免竞态;推荐testify提升可读性但需注意assert与require语义差异。
Go 的测试不是靠第三方库驱动的,go test 命令和 testing 包原生支持,写法简单但容易忽略边界和组织逻辑。
测试文件命名和位置必须严格匹配
Go 要求测试文件名以 _test.go 结尾,且与被测代码放在同一包(即同一目录)下。例如,utils.go 的测试必须写在 utils_test.go 中;如果误写成 test_utils.go 或放在其他目录,go test 会直接跳过。
- 测试文件中可定义
TestXxx函数(首字母大写,Xxx 非小写),否则不被识别为测试用例 - 若想测试内部未导出函数(如
parseInput),测试文件必须和源文件同包(不能新建utils_test包) - 跨包测试只能调用已导出(首字母大写)的符号,无法直接测私有逻辑
使用 t.Run 组织子测试,避免变量捕获陷阱
循环中直接用 for _, tc := range cases 调 t.Run 时,闭包常捕获循环变量地址,导致所有子测试读到同一个 tc 值。这是新手高频翻车点。
// ❌ 错误写法:所有子测试共享 tc 的最终值
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if got := SomeFunc(tc.input); got != tc.want {
t.Errorf("got %v, want %v", got, tc.want)
}
})
}
// ✅ 正确写法:显式复制变量或用索引
for _, tc := range tests {
tc := tc // 创建新变量绑定
t.Run(tc.name, func(t *testing.T) {
if got := SomeFunc(tc.input); got != tc.want {
t.Errorf("got %v, want %v", got, tc.want)
}
})
}
慎用 t.Parallel(),注意资源竞争和初始化顺序
加 t.Parallel() 可加速测试执行,但它只保证子测试间并行,不保证与其他测试(包括非并行测试)隔离。若多个测试共用全局状态(如修改包级变量、临时文件、数据库连接池),极易出现随机失败。