如何使用“测试”包在 Go 测试中打印?
Posted
技术标签:
【中文标题】如何使用“测试”包在 Go 测试中打印?【英文标题】:How do you print in a Go test using the "testing" package? 【发布时间】:2014-06-05 23:47:25 【问题描述】:我正在 Go 中运行一个测试,其中包含打印某些内容(即用于调试测试)的语句,但它没有打印任何内容。
func TestPrintSomething(t *testing.T)
fmt.Println("Say hi")
当我对该文件运行 go test 时,输出如下:
ok command-line-arguments 0.004s
据我所知,真正让它打印的唯一方法是通过 t.Error() 打印它,如下所示:
func TestPrintSomethingAgain(t *testing.T)
t.Error("Say hi")
哪个输出这个:
Say hi
--- FAIL: TestPrintSomethingAgain (0.00 seconds)
foo_test.go:35: Say hi
FAIL
FAIL command-line-arguments 0.003s
gom: exit status 1
我用谷歌搜索并查看了手册,但没有找到任何东西。
【问题讨论】:
这可能适用于 Go 1.14(2010 年第一季度)。见my answer below。 @VonC s/b Q1 2020 @user2133814 同意,确实应该是 2020 年,而不是 2010 年。answer below 确实提到了 2020 年。我已经编辑了上述答案,并参考了 Dave Cheney 关于该新功能的文章。 【参考方案1】:
t.Log()
直到测试完成后才会显示,因此如果您尝试调试挂起或性能不佳的测试,您似乎需要使用fmt
。
是的:在 Go 1.13(2019 年 8 月)之前就是这种情况。
随后在golang.org
issue 24929
考虑以下(愚蠢的)自动化测试:
func TestFoo(t *testing.T) t.Parallel() for i := 0; i < 15; i++ t.Logf("%d", i) time.Sleep(3 * time.Second) func TestBar(t *testing.T) t.Parallel() for i := 0; i < 15; i++ t.Logf("%d", i) time.Sleep(2 * time.Second) func TestBaz(t *testing.T) t.Parallel() for i := 0; i < 15; i++ t.Logf("%d", i) time.Sleep(1 * time.Second)
如果我运行
在本地迭代时,我希望能够进行更改,运行我的测试,立即查看日志中发生的情况以了解正在发生的情况,如有必要,请按 CTRL+C 提前关闭测试,进行另一项更改,重新运行测试,等等。 如果go test -v
,在所有TestFoo
完成之前没有日志输出,然后在所有TestBar
完成之前没有输出,并且在所有之前没有更多输出TestBaz
的已完成。 如果测试正常,这很好,但如果存在某种错误,则在某些情况下缓冲日志输出会出现问题:TestFoo
很慢(例如,它是一个集成测试),我会在测试结束之前得到任何日志输出。这会显着减慢迭代速度。 如果TestFoo
有一个错误导致它挂起并且永远不会完成,我将不会得到任何日志输出。在这些情况下,t.Log
和t.Logf
根本没有用处。 这使得调试非常困难。 此外,不仅没有日志输出,而且如果测试挂起的时间过长,Go 测试超时会在 10 分钟后终止测试,或者如果我增加超时,许多 CI 服务器也会终止测试,如果一段时间后(例如,CircleCI 中的 10 分钟)没有日志输出。 所以现在我的测试被终止了,日志中没有任何内容可以告诉我发生了什么。
但对于(可能)Go 1.14(2020 年第一季度):CL 127120
测试:详细模式下的流式日志输出
现在的输出是:
=== RUN TestFoo
=== PAUSE TestFoo
=== RUN TestBar
=== PAUSE TestBar
=== RUN TestBaz
=== PAUSE TestBaz
=== CONT TestFoo
=== CONT TestBaz
main_test.go:30: 0
=== CONT TestFoo
main_test.go:12: 0
=== CONT TestBar
main_test.go:21: 0
=== CONT TestBaz
main_test.go:30: 1
main_test.go:30: 2
=== CONT TestBar
main_test.go:21: 1
=== CONT TestFoo
main_test.go:12: 1
=== CONT TestBaz
main_test.go:30: 3
main_test.go:30: 4
=== CONT TestBar
main_test.go:21: 2
=== CONT TestBaz
main_test.go:30: 5
=== CONT TestFoo
main_test.go:12: 2
=== CONT TestBar
main_test.go:21: 3
=== CONT TestBaz
main_test.go:30: 6
main_test.go:30: 7
=== CONT TestBar
main_test.go:21: 4
=== CONT TestBaz
main_test.go:30: 8
=== CONT TestFoo
main_test.go:12: 3
=== CONT TestBaz
main_test.go:30: 9
=== CONT TestBar
main_test.go:21: 5
=== CONT TestBaz
main_test.go:30: 10
main_test.go:30: 11
=== CONT TestFoo
main_test.go:12: 4
=== CONT TestBar
main_test.go:21: 6
=== CONT TestBaz
main_test.go:30: 12
main_test.go:30: 13
=== CONT TestBar
main_test.go:21: 7
=== CONT TestBaz
main_test.go:30: 14
=== CONT TestFoo
main_test.go:12: 5
--- PASS: TestBaz (15.01s)
=== CONT TestBar
main_test.go:21: 8
=== CONT TestFoo
main_test.go:12: 6
=== CONT TestBar
main_test.go:21: 9
main_test.go:21: 10
=== CONT TestFoo
main_test.go:12: 7
=== CONT TestBar
main_test.go:21: 11
=== CONT TestFoo
main_test.go:12: 8
=== CONT TestBar
main_test.go:21: 12
main_test.go:21: 13
=== CONT TestFoo
main_test.go:12: 9
=== CONT TestBar
main_test.go:21: 14
=== CONT TestFoo
main_test.go:12: 10
--- PASS: TestBar (30.01s)
=== CONT TestFoo
main_test.go:12: 11
main_test.go:12: 12
main_test.go:12: 13
main_test.go:12: 14
--- PASS: TestFoo (45.02s)
PASS
ok command-line-arguments 45.022s
正如 Dave Cheney 在“go test -v
streaming output”中证明的那样,它确实在 Go 1.14 中:
在 Go 1.14 中,
go test -v
将流式传输t.Log
输出发生时,而不是囤积它直到测试运行结束。
在 Go 1.14 下,
fmt.Println
和t.Log
行是交错的,而不是等待测试完成,这表明在使用go test -v
时测试输出是流式传输的。
优势,据 Dave 所说:
对于经常在测试失败时重试很长一段时间的集成式测试来说,这是一项极大的生活质量改进。 流式传输
t.Log
输出将帮助 Gophers 调试这些测试失败,而无需等到整个测试超时才能接收它们的输出。
【讨论】:
照明,谢谢! :) 只是一件事,测试输出与此处的测试不匹配。 @bravmi 好点。你能用正确的更新输出编辑答案吗? 很高兴,一旦编辑队列释放了!让我借此机会非常感谢您的回答。 【参考方案2】:如果您使用testing.M
和相关的设置/拆卸; -v
在这里也有效。
package g
import (
"os"
"fmt"
"testing"
)
func TestSomething(t *testing.T)
t.Skip("later")
func setup()
fmt.Println("setting up")
func teardown()
fmt.Println("tearing down")
func TestMain(m *testing.M)
setup()
result := m.Run()
teardown()
os.Exit(result)
$ go test -v g_test.go
setting up
=== RUN TestSomething
g_test.go:10: later
--- SKIP: TestSomething (0.00s)
PASS
tearing down
ok command-line-arguments 0.002s
【讨论】:
【参考方案3】:t.Log
和 t.Logf
确实会在您的测试中打印出来,但由于它与您的测试打印在同一行上,因此经常会被遗漏。我所做的是以使它们脱颖而出的方式记录它们,即
t.Run("FindIntercomUserAndReturnID should find an intercom user", func(t *testing.T)
id, err := ic.FindIntercomUserAndReturnID("test3@test.com")
assert.Nil(t, err)
assert.NotNil(t, id)
t.Logf("\n\nid: %v\n\n", *id)
)
将其打印到终端,
=== RUN TestIntercom
=== RUN TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user
TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user: intercom_test.go:34:
id: 5ea8caed05a4862c0d712008
--- PASS: TestIntercom (1.45s)
--- PASS: TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user (1.45s)
PASS
ok github.com/RuNpiXelruN/third-party-delete-service 1.470s
【讨论】:
【参考方案4】:例如,
package verbose
import (
"fmt"
"testing"
)
func TestPrintSomething(t *testing.T)
fmt.Println("Say hi")
t.Log("Say bye")
go test -v
=== RUN TestPrintSomething
Say hi
--- PASS: TestPrintSomething (0.00 seconds)
v_test.go:10: Say bye
PASS
ok so/v 0.002s
Command go
Description of testing flags
-v Verbose output: log all tests as they are run. Also print all text from Log and Logf calls even if the test succeeds.
Package testing
func (*T) Log
func (c *T) Log(args ...interface)
Log 使用默认格式格式化其参数,类似于 Println,并将文本记录在错误日志中。对于测试,仅当测试失败或设置了 -test.v 标志时才会打印文本。对于基准测试,总是打印文本以避免性能取决于 -test.v 标志的值。
【讨论】:
verbose
是我要找的。span>
anwa 查看你正在测试的方法中的日志输出
我不能在这里使用 fmt,因为 Visual Studio Code 删除了 fmt 的导入!
在Example_xxx()中似乎verbose不起作用。【参考方案5】:
结构 testing.T
和 testing.B
都有一个 .Log
和 .Logf
方法,听起来就是你要找的。 .Log
和 .Logf
分别类似于 fmt.Print
和 fmt.Printf
。
在此处查看更多详细信息:http://golang.org/pkg/testing/#pkg-index
fmt.X
打印语句 do 在测试中起作用,但是您会发现它们的输出可能不在您希望找到的屏幕上,因此,为什么应该使用 @ 中的日志记录方法987654341@.
如果您想查看没有失败的测试的日志,则必须提供go test
-v
标志(v 表示详细程度)。更多关于测试标志的细节可以在这里找到:https://golang.org/cmd/go/#hdr-Testing_flags
【讨论】:
t.Log() 直到测试完成后才会显示,因此如果您尝试调试挂起或性能不佳的测试,您似乎需要使用 fmt。请参阅 PeterSO 的回答,了解在运行测试时使用 go test -v 显示 fmt.Println 的输出。 如果有人从 VSCode 运行测试,只需在您的 settings.json 中添加"go.testFlags": ["-v"]
(来源:github.com/Microsoft/vscode-go/issues/1377)【参考方案6】:
*_test.go
文件和其他文件一样是 Go 源文件,如果需要转储复杂的数据结构,每次都可以初始化一个新的记录器,这里是一个示例:
// initZapLog is delegated to initialize a new 'log manager'
func initZapLog() *zap.Logger
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
config.EncoderConfig.TimeKey = "timestamp"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, _ := config.Build()
return logger
然后,每次,在每个测试中:
func TestCreateDB(t *testing.T)
loggerMgr := initZapLog()
// Make logger avaible everywhere
zap.ReplaceGlobals(loggerMgr)
defer loggerMgr.Sync() // flushes buffer, if any
logger := loggerMgr.Sugar()
logger.Debug("START")
conf := initConf()
/* Your test here
if false
t.Fail()
*/
【讨论】:
【参考方案7】:有时我会进行测试
fmt.Fprintln(os.Stdout, "hello")
另外,您可以打印到:
fmt.Fprintln(os.Stderr, "hello)
【讨论】:
第一个可以是fmt.Println("hello")
。
Visual Studio Code 在我尝试导入和使用时删除了 import fmt。 :(
@micahhoover 这是预期的行为,是未使用导入,go 工具将删除它,因为它不会编译,添加 fmt.Fprintln(os.Stderr, "hello)首先以上是关于如何使用“测试”包在 Go 测试中打印?的主要内容,如果未能解决你的问题,请参考以下文章