How do you print in a Go test using the "testing" package?

The structs testing.T and testing.B both have a .Log and .Logf method that sound to be what you are looking for. .Log and .Logf are similar to fmt.Print and fmt.Printf respectively.

See more details here: http://golang.org/pkg/testing/#pkg-index

fmt.X print statements do work inside tests, but you will find their output is probably not on screen where you expect to find it and, hence, why you should use the logging methods in 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


For example,

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 formats its arguments using default formatting, analogous to Println, and records the text in the error log. For tests, the text will be printed only if the test fails or the -test.v flag is set. For benchmarks, the text is always printed to avoid having performance depend on the value of the -test.v flag.


t.Log() will not show up until after the test is complete, so if you're trying to debug a test that is hanging or performing badly it seems you need to use fmt.

Yes: that was the case up to Go 1.13 (August 2019) included.

And that was followed in golang.org issue 24929

Consider the following (silly) automated tests:

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

If I run go test -v, I get no log output until all of TestFoo is done, then no output until all of TestBar is done, and again no more output until all of TestBaz is done.
This is fine if the tests are working, but if there is some sort of bug, there are a few cases where buffering log output is problematic:

  • When iterating locally, I want to be able to make a change, run my tests, see what's happening in the logs immediately to understand what's going on, hit CTRL+C to shut the test down early if necessary, make another change, re-run the tests, and so on.
    If TestFoo is slow (e.g., it's an integration test), I get no log output until the very end of the test. This significantly slows down iteration.
  • If TestFoo has a bug that causes it to hang and never complete, I'd get no log output whatsoever. In these cases, t.Log and t.Logf are of no use at all.
    This makes debugging very difficult.
  • Moreover, not only do I get no log output, but if the test hangs too long, either the Go test timeout kills the test after 10 minutes, or if I increase that timeout, many CI servers will also kill off tests if there is no log output after a certain amount of time (e.g., 10 minutes in CircleCI).
    So now my tests are killed and I have nothing in the logs to tell me what happened.

But for (possibly) Go 1.14 (Q1 2020): CL 127120

testing: stream log output in verbose mode

The output now is:

=== 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

It is indeed in Go 1.14, as Dave Cheney attests in "go test -v streaming output":

In Go 1.14, go test -v will stream t.Log output as it happens, rather than hoarding it til the end of the test run.

Under Go 1.14 the fmt.Println and t.Log lines are interleaved, rather than waiting for the test to complete, demonstrating that test output is streamed when go test -v is used.

Advantage, according to Dave:

This is a great quality of life improvement for integration style tests that often retry for long periods when the test is failing.
Streaming t.Log output will help Gophers debug those test failures without having to wait until the entire test times out to receive their output.