t.Log 仅在 -v 模式下输出,带时间戳和测试名前缀;不影响测试状态,与 t.Errorf(标记失败)和 t.Fatal(终止测试)行为不同;需避免滥用、混用 log 包,并注意并发与作用域限制。

t.Log 只在 -v 模式下才可见
测试里调用 t.Log 不会自动打印到终端,这是最常被卡住的地方。它只在显式启用详细模式时输出,否则完全静默——不是失效,是“藏起来了”。
- 运行测试必须加
-v参数:go test -v或go test -v ./... - 如果用了
go test -run=TestFoo但没加-v,t.Log的内容就彻底看不到 -
t.Log输出带时间戳和测试名前缀(如TestFoo: hello),方便定位来源 - 别用
fmt.Println替代——它不绑定测试生命周期,可能干扰并行测试或被截断
t.Log 和 t.Errorf 的行为差异
t.Log 是纯记录,不影响测试状态;t.Errorf 则标记失败但继续执行。很多人误以为 t.Log 能“替代断言”,其实它连失败信号都不发。
-
t.Log("got:", got, "want:", want)—— 仅打印,测试仍算通过 -
t.Errorf("mismatch: got %v, want %v", got, want)—— 打印 + 标记失败 + 继续跑完当前测试函数 - 想“失败即停”,得用
t.Fatal或t.Fatalf,它们会终止当前测试函数 - 注意:并发测试中,多个 goroutine 同时调用
t.Log的输出可能交错,但不会 panic
测试中日志太多?用 t.Helper 配合条件控制
调试阶段频繁加 t.Log 很自然,但上线前全删又容易漏。更稳的做法是封装一层可开关的调试日志,而不是依赖注释/删代码。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 定义一个调试开关变量:
var debug = os.Getenv("TEST_DEBUG") != "" - 在需要处加判断:
if debug { t.Log("step x:", val) } - 配合
t.Helper()让日志行号指向调用处而非封装函数内部(否则堆栈跳转错乱) - 避免在循环里无条件打
t.Log——尤其大数据量时会拖慢测试、刷屏难定位
log 包和 t.Log 混用会出问题吗?
可以混用,但效果不同:log.Printf 输出到标准错误且无测试上下文;t.Log 输出受测试框架管理,支持 -v 控制、失败关联、并行安全。
立即学习“go语言免费学习笔记(深入)”;
-
log.Printf的输出永远可见,不受-v影响,但无法区分是哪个测试打的 - 在子 goroutine 里用
t.Log是安全的(t 是传入的,非全局),但必须确保该 goroutine 在测试函数返回前结束,否则日志可能丢失或 panic - 别在
init()或包级变量初始化里调用t.Log——t 此时根本不存在 - 如果测试用了
t.Parallel(),t.Log依然有效,但输出顺序不保证与执行顺序一致
t.Log 都有明确目的:要么辅助定位某次失败,要么验证中间状态是否符合预期。忘了加 -v 是最常见失手点,建议把 alias gt='go test -v' 加进 shell 配置。


















