_test.go 是 Go 测试文件的强制后缀,必须与被测源码同目录同包名,否则 go test 工具链无法识别;文件名、路径、包声明三者缺一不可,偏离任一条件测试将被忽略或编译失败。

_test.go 是 Go 测试文件的强制后缀,不是建议,是 go test 工具链识别测试的唯一依据——没有它,你的测试函数再规范也不会被运行。
为什么必须叫 xxx_test.go?
Go 的测试发现机制完全依赖文件名后缀,而非包声明或函数前缀。工具链在执行 go test 时,只扫描所有以 _test.go 结尾的文件,然后进一步筛选其中以 Test 开头的函数。其他命名(如 test_xxx.go、xxx_test.go 但放在错误目录)都会被直接忽略。
测试文件该放在哪?包名怎么写?
测试文件应与被测源码同目录、同包名,例如:
-
user/user.go→ 测试文件为user/user_test.go,包声明为package user - 这样可直接调用非导出函数(小写开头),做白盒测试
- 若需黑盒测试(仅测导出 API),可用外部测试包:文件仍为
user/user_test.go,但包声明为package user_test—— 此时无法访问user包内未导出的符号
常见命名错误及后果
这些写法看似合理,但实际会导致测试失效:
-
user_test.go放在项目根目录(而非user/子目录)→go test找不到对应包,报错no buildable Go source files -
user_tests.go或test_user.go→ 文件被完全跳过,go test -v不显示任何测试项 -
user_test.go中包名写成package main→ 编译失败:cannot use package main in test - Windows 下写成
User_test.go(首字母大写)→ 可能因文件系统不区分大小写导致冲突或不可移植
表驱动测试中子测试的命名建议
虽然测试函数本身必须叫 TestXxx,但内部用 t.Run() 定义的子测试名没有语法限制,但强烈建议用下划线分隔的描述性名称,便于定位失败场景:
func TestParseConfig(t *testing.T) {
tests := map[string]struct{
input string
wantErr bool
}{
"empty_string": {input: "", wantErr: true},
"valid_json": {input: `{"port":8080}`, wantErr: false},
"invalid_json": {input: `{port:8080}`, wantErr: true},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// 实际测试逻辑
})
}
}这样失败时输出是 --- FAIL: TestParseConfig/empty_string,一眼知道哪个 case 崩了。
Go 测试命名看着简单,但一旦偏离 _test.go + 同目录 + 同包这三条铁律,就等于没写测试——因为工具链根本看不见。最容易被忽略的是「目录位置」和「包名一致性」,尤其在重构或新增子包时,多花 10 秒确认路径和 package 声明,能省掉半小时排查「为什么 test 不跑」的时间。










