Go测试中必须用t.Log/t.Logf而非fmt.Println输出日志,因testing包默认屏蔽标准输出;t.Log适用于简单打印,t.Logf支持格式化;日志仅在-go test -v时显示,且敏感信息不应记录。

Go 测试中不能直接用 fmt.Println 输出调试日志,因为测试运行时标准输出会被捕获或静默;必须使用 t.Log 或 t.Logf 才能在 go test -v 下看到内容。
为什么 fmt.Println 在测试里“没输出”
Go 的 testing 包默认屏蔽 os.Stdout 和 os.Stderr,防止测试干扰 CI 日志或污染结果。即使你写了 fmt.Println("debug"),它也不会出现在 go test 的终端里(除非加 -v 且该行恰好在失败时被打印,但不可靠)。
-
t.Log和t.Logf是唯一被测试框架认可的日志入口,内容只在-v模式下显示 - 不加
-v时,t.Log不会输出,也不会影响测试通过性 - 如果测试 panic 或失败,
t.Log的历史记录会随错误一起打印出来
t.Log vs t.Logf:什么时候用哪个
两者行为完全一致,区别仅在于参数处理方式——t.Log 直接打印所有参数值(类似 fmt.Print),t.Logf 支持格式化字符串(类似 fmt.Printf)。
- 打印简单变量:
t.Log("value:", x, "err:", err) - 需要格式控制(如截断、对齐、JSON):
t.Logf("request: %+v, status: %d", req, resp.StatusCode) - 避免拼接字符串开销(尤其循环内):
t.Log("index", i, "found", item)比t.Log("index " + strconv.Itoa(i) + " found " + item)更安全高效
测试日志的可见性与性能陷阱
日志本身不改变测试逻辑,但滥用会影响可读性和执行效率。
- 高频调用(比如在 10w 次循环里每轮
t.Log)会显著拖慢测试,且日志爆炸难以定位关键信息 -
敏感数据(token、密码、用户 ID)不要进
t.Log,CI 日志可能被存档或共享 - 想临时禁用某段日志?注释掉即可,无需改逻辑;别用条件包装
t.Log来“开关”,那会让调试意图模糊 - 结构体日志建议用
%+v而非%v,否则匿名字段和未导出字段看不到
替代方案:只在调试时输出的灵活写法
有时你只想在本地调试看日志,又不想每次跑测试都加 -v,可以结合环境变量或构建标签:
if os.Getenv("DEBUG") != "" {
fmt.Printf("DEBUG: processing %v\n", item)
}
这种写法绕过 t.Log 限制,但要注意:它不会出现在 go test -v 报告里,也不受测试生命周期管理——比如测试 panic 后这部分日志可能丢失。
真正可靠的调试日志,始终以 t.Log 为第一选择;其它方式只是权宜之计,容易漏掉上下文或误判执行路径。











