go test 默认仅运行当前包的Test*函数,不递归子目录或加载外部测试;需用./...测整个模块,-run支持正则匹配函数名,t.Log在-v下显示而fmt.Println不显示。

go test 默认行为:只跑当前包的测试函数
运行 go test 时,它不会递归查找子目录,也不会自动加载外部依赖的测试代码,只编译并执行当前目录下以 _test.go 结尾、且包含 Test* 前缀函数的文件。常见误解是以为加了 -v 就能看见所有包的测试,其实只是让输出更详细而已。
容易踩的坑:
- 在项目根目录下执行
go test,结果提示no buildable Go source files——因为根目录通常没有.go源文件,只有main.go或go.mod - 想测整个模块却只写了
go test,实际应使用go test ./... - 测试文件里用了
package main(比如复制了主程序代码),会导致编译失败:cannot use test file *_test.go with package main
如何指定运行某个测试函数或某组测试
go test -run 是最常用的筛选方式,支持正则匹配,但注意它只匹配函数名(不包括包名或路径)。
实操建议:
- 只跑
TestOpenFile:go test -run TestOpenFile - 跑所有以
TestHTTP开头的函数:go test -run ^TestHTTP(^表示开头,需用引号包裹避免 shell 解析:go test -run "^TestHTTP") - 跳过某类测试(比如集成类):
go test -run "^(?!TestIntegration).*$",但更推荐用-tags或构建约束 - 函数名含下划线或数字?没问题,
-run匹配的是 Go 标识符本身,不是文件名
为什么 go test -v 输出没看到日志或 fmt.Println
go test 默认会捕获测试函数中所有标准输出(包括 fmt.Println、t.Log),只有测试失败或加了 -v 才显示 t.Log;而 fmt.Println 即使加了 -v 也不会输出——这是设计使然,防止干扰测试结果判断。
正确做法:
- 用
t.Log("msg")替代fmt.Println,它会在-v下显示,且带时间戳和测试名前缀 - 调试时临时加
t.Logf("val=%v", x),比打日志更安全 - 如果真要强制刷出
fmt内容(极少见),得加-args并手动 flush:fmt.Fprintln(os.Stdout, "hello"); os.Stdout.Sync(),但不推荐
go test 跑得慢?检查是否误启了 race 检测或 coverage
go test -race 和 go test -cover 都会让编译器插入额外逻辑,显著拖慢执行速度,尤其在大量 goroutine 或循环密集型测试中。本地日常开发建议关闭它们,除非明确需要检测竞态或统计覆盖率。
性能相关要点:
-
-race会让每个内存访问都走检测桩,慢 5–10 倍很常见;启用后还会禁止部分优化,可能掩盖真实性能问题 -
-cover启用后,即使只加-covermode=count,也会在每行插入计数器,影响分支预测和缓存局部性 - CI 中跑覆盖率可以接受,但开发时别养成
alias gt='go test -v -race -cover'这种习惯 - 想快速验证逻辑?直接
go test或go test -v就够了
init()、全局变量、或未清理的临时目录,是比命令参数更隐蔽的性能/稳定性杀手。这些不会报错,但会让测试间产生状态污染,有时只在 CI 上偶然失败。










