_test.go 是 Go 测试文件的强制后缀,必须与被测源码同目录同包名,否则 go test 工具链无法识别;文件名、路径、包声明三者缺一不可,偏离任一条件测试将被忽略或编译失败。
_test.go 是 Go 测试文件的强制后缀,不是建议,是 go test 工具链识别测试的唯一依据——没有它,你的测试函数再规范也不会被运行。
Go 的测试发现机制完全依赖文件名后缀,而非包声明或函数前缀。工具链在执行 go test 时,只扫描所有以 _test.go 结尾的文件,然后进一步筛选其中以 Test 开头的函数。其他命名(如 test_xxx.go、xxx_test.go 但放在错误目录)都会被直接忽略。
测试文件应与被测源码同目录、同包名,例如:
user/user.go → 测试文件为 user/user_test.go,包声明为 package user
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
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 不跑」的时间。