如何在 Go 测试中输出数据:2025 年 t.Log() 和 t.Logf() 的秘密

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:永恒的问题“如何在测试中输出一些内容?”

\n\n

您正在编写一个 Go 测试。逻辑复杂,数据混乱,您迫切需要看到内部发生了什么。您下意识地写下 fmt.Println("value =", x),运行测试……然后看到一片寂静。没有任何输出。熟悉吗?

\n\n

这个问题是 Stack Overflow 上 Go 开发者(不仅仅是初学者!)中最常见的问题之一。似乎输出一行字符串能有多难?但在 Go 测试的世界里,有自己的规则和一套得体的工具。在本文中,我们将剖析测试中所有输出方式,梳理 2025 年的最佳实践,并展示如何避免犯错。开始吧!

\n\n

为什么 fmt.Println 保持沉默?(以及它何时才会开口)

\n\n

让我们直接进入正题。当您使用 go test 命令(不带标志)运行测试时,标准输出(stdout)会被抑制。Go 测试框架认为,如果测试成功通过,用户就不需要看到大量的调试信息。这样做是为了保持输出的整洁和自动化——想象一下,如果每次运行 CI/CD 时每个测试都输出 10 行日志会怎样。

\n\n

然而,有两种例外情况,fmt.Println 的输出仍然会显示在屏幕上:

\n
    \n
  • -v 标志(详细模式): go test -v。此模式会启用所有测试的详细输出。您将看到来自 fmt.Println 和其他函数的消息。
  • \n
  • 测试失败: 如果测试以错误结束(调用了 t.Error 或 t.Fatal),那么来自该测试的 fmt.Println 输出将会显示。这对于调试非常有用。
  • \n
\n\n

但是,依赖 fmt.Println 是不合时宜的。对于 Go 测试,有专门、更正确且更强大的工具。

\n\n

派对之王:t.Log() 和 t.Logf()

\n\n

testing.T 对象(传递给每个测试)具有内置的日志记录方法。请像记住“主祷文”一样记住它们:t.Log() 和 t.Logf()。

\n\n
package main\n\nimport (\n    "testing"\n)\n\nfunc TestSum(t *testing.T) {\n    result := 2 + 2\n    // 简单日志记录\n    t.Log("开始求和测试")\n    t.Log("计算结果:", result)\n\n    // 带格式的日志记录(类似 fmt.Printf)\n    t.Logf("2 加 2 的和是 %d。检查通过!", result)\n\n    if result != 4 {\n        t.Errorf("期望得到 4,但得到 %d", result)\n    }\n}
\n\n

使用 -v 标志运行此测试:

\n
go test -v -run TestSum
\n\n

您将在测试输出中看到漂亮、结构化的消息。

\n\n

为什么 t.Log 比 fmt.Println 更好?

\n
    \n
  • 上下文: 来自 t.Log 的消息会自动关联到特定的测试。在 -v 输出中,您可以看到哪个测试打印了什么。
  • \n
  • 可控性: t.Log 的输出仅在使用了 -v 标志或测试失败时显示。这意味着您的日志不会在常规运行时污染控制台。
  • \n
  • 安全性: 与 fmt.Fprintf(os.Stderr, ...) 不同,t.Log 能正确处理并行测试(t.Parallel)并且不会引发竞态条件。
  • \n
\n\n

原力的黑暗面:t.Error() 和 t.Fatal() 作为输出工具

\n\n

许多新手使用 t.Error() 仅仅是为了在出错时停止测试。但实际上,这是输出重要诊断信息的绝佳(且正确!)方式,尤其是在测试失败时。

\n\n

秘诀在于,传递给 t.Error() 或 t.Fatal() 的消息始终会显示,即使没有 -v 标志。这使得它们成为输出关键信息的理想选择。

博客

书籍推荐