ChatGPT解决这个技术问题 Extra ChatGPT

如何使用“测试”包在 Go 测试中打印?

我在 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 2020 年第一季度
@user2133814 同意,确实应该是 2020 年,而不是 2010 年。answer below 确实提到了 2020 年。我已经编辑了上述答案,并参考了 Dave Cheney 关于该新功能的文章。

P
Pang

结构 testing.Ttesting.B 都有一个 .Log.Logf 方法,听起来就是您正在寻找的。 .Log.Logf 分别类似于 fmt.Printfmt.Printf

在此处查看更多详细信息:http://golang.org/pkg/testing/#pkg-index

fmt.X 打印语句确实在测试中工作,但您会发现它们的输出可能不在您希望找到的屏幕上,因此,您应该使用 testing 中的日志记录方法。

如果像您的情况一样,您想查看未失败的测试的日志,则必须提供 go test -v 标志(v 表示详细程度)。可以在此处找到有关测试标志的更多详细信息:https://golang.org/cmd/go/#hdr-Testing_flags


t.Log() 直到测试完成后才会显示,因此如果您尝试调试挂起或性能不佳的测试,您似乎需要使用 fmt。有关使用 go test -v 在运行测试时显示 fmt.Println 的输出,请参阅 PeterSO 的答案。
如果有人从 VSCode 运行测试,只需在您的 settings.json 中添加 "go.testFlags": ["-v"](来源:github.com/Microsoft/vscode-go/issues/1377
P
Pang

例如,

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

命令 go 测试标志的描述 -v 详细输出:记录所有运行的测试。即使测试成功,也要打印来自 Log 和 Logf 调用的所有文本。

包测试 func (*T) Log func (c *T) Log(args ...interface{}) Log 使用默认格式格式化其参数,类似于 Println,并将文本记录在错误日志中。对于测试,仅当测试失败或设置了 -test.v 标志时才会打印文本。对于基准测试,总是打印文本以避免性能取决于 -test.v 标志的值。


verbose 是我一直在寻找的。
anwa 以您正在测试的方式查看日志输出
我不能在这里使用 fmt,因为 Visual Studio Code 删除了 fmt 的导入!
似乎详细在 Example_xxx() 中不起作用。
似乎 v 标志仅在测试成功时生效,即使测试失败如何记录?
b
bravmi

t.Log() 直到测试完成后才会显示,因此如果您尝试调试挂起或性能不佳的测试,您似乎需要使用 fmt。

是的:在 Go 1.13(2019 年 8 月)之前就是这种情况。

然后在 golang.org issue 24929

考虑以下(愚蠢的)自动化测试: func TestFoo(t *testing.T) { t.Parallel() for i := 0;我 < 15; i++ { t.Logf("%d", i) time.Sleep(3 * time.Second) } } func TestBar(t *testing.T) { t.Parallel() for i := 0;我 < 15; i++ { t.Logf("%d", i) time.Sleep(2 * time.Second) } } func TestBaz(t *testing.T) { t.Parallel() for i := 0;我 < 15; i++ { t.Logf("%d", i) time.Sleep(1 * time.Second) } } 如果我运行 go test -v,在完成所有 TestFoo 之前我没有日志输出,然后直到所有TestBar 完成,并且在所有 TestBaz 完成之前不再有输出。如果测试正常,这很好,但如果存在某种错误,在某些情况下缓冲日志输出会出现问题:在本地迭代时,我希望能够进行更改,运行我的测试,看看是什么立即在日志中发生以了解正在发生的事情,如有必要,请按 CTRL+C 提前关闭测试,进行另一项更改,重新运行测试,等等。如果 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 时测试输出是流式传输的。

优势,据戴夫说:

对于在测试失败时通常会长时间重试的集成样式测试来说,这是一个极大的生活质量改进。流式传输 t.Log 输出将帮助 Gophers 调试这些测试失败,而无需等到整个测试超时才能接收它们的输出。


发光,谢谢! :) 只是一件事,测试输出与此处的测试不匹配。
@bravmi 好点。您可以使用正确的更新输出编辑答案吗?
我的荣幸,一旦编辑队列释放!让我借此机会非常感谢您的回答。 <3
E
Eddy Hernandez

有时我会进行测试

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)
R
RuNpiXelruN

t.Logt.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

R
Ronald Petty

如果您使用 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

a
alessiosavi

*_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()
    }*/
}