在Go语言测试中,如何使用“testing”包进行打印呢?

esbemjvw  于 2022-12-25  发布在  Go
关注(0)|答案(8)|浏览(416)

我在Go语言中运行了一个测试,用一条语句来打印一些东西(例如,调试测试),但是它什么也没有打印。

func TestPrintSomething(t *testing.T) {
    fmt.Println("Say hi")
}

当我在这个文件上运行go测试时,输出如下:

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

我在谷歌上搜索了一下说明书,但什么也没找到。

k3bvogb1

k3bvogb11#

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

cetgtptt2#

结构体testing.Ttesting.B都有一个.Log.Logf方法,听起来就是您要查找的。.Log.Logf分别与fmt.Printfmt.Printf类似。
See more details here: http://golang.org/pkg/testing/#pkg-index
fmt.X print语句确实在测试内部工作,但是您会发现它们的输出可能不在您期望找到它的屏幕上,因此,您应该使用testing中的日志记录方法。
If, as in your case, you want to see the logs for tests that are not failing, you have to provide go test the -v flag (v for verbosity). More details on testing flags can be found here: https://golang.org/cmd/go/#hdr-Testing_flags

c86crjj0

c86crjj03#

例如,

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
测试标志说明

-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
函数(*T)日志

func (c *T) Log(args ...interface{})

日志使用默认格式设置其参数的格式(类似于Println),并在错误日志中记录文本。对于测试,仅当测试失败或设置了-test.v标志时才打印文本。对于基准,始终打印文本以避免性能依赖于-test.v标志的值。

iih3973s

iih3973s4#

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)
  }
}

如果我运行go test -vTestFoo全部完成之前没有日志输出,然后在TestBar全部完成之前没有输出,再次在TestBaz全部完成之前没有输出。
如果测试正常运行,这是很好的,但是如果存在某种bug,那么在一些情况下缓冲日志输出会有问题:

  • 在本地迭代时,我希望能够进行更改、运行测试、立即查看日志中发生的事情以了解正在发生的事情、按CTRL+C在必要时提前关闭测试、进行另一个更改、重新运行测试等等。

如果TestFoo很慢(例如,它是一个集成测试),那么直到测试结束之前我都不会得到日志输出,这会显著地减慢迭代。

  • 如果TestFoo有一个bug,导致它挂起并且永远无法完成,我将不会得到任何日志输出,在这种情况下,t.Logt.Logf根本没有用。

这使得调试非常困难。

  • 此外,不仅没有日志输出,而且如果测试挂起太久,Go测试超时会在10分钟后终止测试,或者如果我增加超时,如果在一定时间后(例如,在CircleCI中为10分钟)没有日志输出,许多CI服务器也会终止测试。

所以现在我的测试被杀了,日志中没有任何东西可以告诉我发生了什么。
但对于(可能)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切尼在“go test -v streaming output“中所证明的那样,Go语言1.14中确实存在这种情况:
在Go语言1.14中,go test -v将在t.Log输出发生时对其进行流式传输,而不是将其存储到测试运行结束时
在Go语言1.14中,fmt.Printlnt.Log行是交错的,而不是等待测试完成,这表明当使用go test -v时,测试输出是流式传输的。
优势,根据戴夫:
对于集成风格的测试来说,这是一个很大的生命质量改进,因为当测试失败时,集成风格的测试经常会长时间地重试。
流式t.Log输出将帮助地鼠调试那些测试失败,而不必等到整个测试超时才接收他们的输出。

snz8szmq

snz8szmq5#

为了测试有时候我会

fmt.Fprintln(os.Stdout, "hello")

此外,您还可以打印到:

fmt.Fprintln(os.Stderr, "hello")
jpfvwuh4

jpfvwuh46#

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
wooyq4lh

wooyq4lh7#

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

wpx232ag8#

警告:一次测试多个软件包时,此处的答案不适用。

来自@VonC和@voidlogic的答案非常棒,但我想提醒大家注意以下线索,以防有人正在运行go test -v ./...的排列:https://github.com/golang/go/issues/46959
问题在于与从多个包运行测试相关的实现细微差别/困难。
例如,运行go test -v -count=1 -run TestOnlyOneInstanceOfThisTestExists ./multiple/packages/exist/below/...将仅在测试完成后打印日志。
但是,运行go test -v -count=1 -run TestOnlyOneInstanceOfThisTestExists ./this/path/points/to/one/package/only/...将按预期流输出。

相关问题