'How to print from go test to console without using verbose option
I want to print an informative message to console from a test, but not have the verbose test output.
I have tried printing from the test using:
fmt.Println("my message") // STDOUTfmt.Fprintln(os.Stderr, "my message") // STDERRt.Log("my message\n") // testing.T log
which all produce the same effect of showing in the console if go test -v is used, but not showing if just go test is used.
However, with go test -v, I also get all the verbose test output like:
=== RUN My_Test
--- PASS: My_Test (0.07s)
go help testflag says:
-v
Verbose output: log all tests as they are run. Also print all
text from Log and Logf calls even if the test succeeds.
but what I want is to not log all tests as they are run, but still print all text from Log and Logf calls even if the test succeeds
Is there a way to print a visible message from within a test, but not see the RUN and PASS messages?
Solution 1:[1]
The testing framework "hijacks" the standard output and error streams for obvious reasons. So no matter what, whether writing to those streams appears in the output is controlled by the testing framework, and it provides no means to "customize" it other than showing or hiding all using the -v flag.
What you may do is use the -json testing flag:
-json
Log verbose output and test results in JSON. This presents the
same information as the -v flag in a machine-readable format.
So you get all the output you would otherwise get with -v, but you have a separate JSON object for each line.
Having this test function:
func TestMy_Test(t *testing.T) {
fmt.Println("[custom] my message from fmt.Println")
}
Output of go test -v .
=== RUN TestMy_Test
[custom] my message from fmt.Println
--- PASS: TestMy_Test (0.00s)
PASS
ok github.com/icza/play 0.002s
Output of go test -json .
{"Time":"2022-05-10T09:26:26.712800797+02:00","Action":"run","Package":"github.com/icza/play","Test":"TestMy_Test"}
{"Time":"2022-05-10T09:26:26.71293072+02:00","Action":"output","Package":"github.com/icza/play","Test":"TestMy_Test","Output":"=== RUN TestMy_Test\n"}
{"Time":"2022-05-10T09:26:26.712946548+02:00","Action":"output","Package":"github.com/icza/play","Test":"TestMy_Test","Output":"[custom] my message from fmt.Println\n"}
{"Time":"2022-05-10T09:26:26.712954637+02:00","Action":"output","Package":"github.com/icza/play","Test":"TestMy_Test","Output":"--- PASS: TestMy_Test (0.00s)\n"}
{"Time":"2022-05-10T09:26:26.712958774+02:00","Action":"pass","Package":"github.com/icza/play","Test":"TestMy_Test","Elapsed":0}
{"Time":"2022-05-10T09:26:26.712964812+02:00","Action":"output","Package":"github.com/icza/play","Output":"PASS\n"}
{"Time":"2022-05-10T09:26:26.713170439+02:00","Action":"output","Package":"github.com/icza/play","Output":"ok \tgithub.com/icza/play\t0.002s\n"}
{"Time":"2022-05-10T09:26:26.713573313+02:00","Action":"pass","Package":"github.com/icza/play","Elapsed":0.003}
You can write a simple app that processes and filters these JSON objects. Or you can filter the output as you could filter any other output.
Output of go test -json . |grep '\[custom\]'
{"Time":"2022-05-10T09:28:24.197077681+02:00","Action":"output","Package":"github.com/icza/play","Test":"TestMy_Test","Output":"[custom] my message from fmt.Println\n"}
If you also want the "pass" or "fail" messages, run go test -json . |grep '"pass"\|"fail"\|\[custom\]'
{"Time":"2022-05-10T09:29:26.069181336+02:00","Action":"output","Package":"github.com/icza/play","Test":"TestMy_Test","Output":"[custom] my message from fmt.Println\n"}
{"Time":"2022-05-10T09:29:26.069189228+02:00","Action":"pass","Package":"github.com/icza/play","Test":"TestMy_Test","Elapsed":0}
{"Time":"2022-05-10T09:29:26.069199239+02:00","Action":"pass","Package":"github.com/icza/play","Elapsed":0}
Solution 2:[2]
You can create you own Log function and use it for printing on screen
func Log(args ...interface{}) {
fmt.Fprintln(os.Stdout, args...)
}
You can also make it to print log based on condition passed through flag
var p = flag.Bool("p", false, "Enable Local Logging")
func MyLog(args ...interface{}) {
if *p {
fmt.Fprintln(os.Stdout, args...)
}
}
Example
package main
import (
"fmt"
"testing"
"os"
"flag"
)
var p = flag.Bool("p", false, "Enable Local Logging")
func Log(args ...interface{}) {
if *p {
fmt.Fprintln(os.Stdout, args...)
}
}
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}
func TestIntMinBasic(t *testing.T) {
ans := IntMin(2, -2)
if ans != -2 {
t.Errorf("IntMin(2, -2) = %d; want -2", ans)
}
}
func TestIntMinTableDriven(t *testing.T) {
var tests = []struct {
a, b int
want int
}{
{0, 1, 0},
{1, 0, 0},
{2, -2, -2},
{0, -1, -1},
{-1, 0, -1},
}
Log("Print to Screen")
for _, tt := range tests {
testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
t.Run(testname, func(t *testing.T) {
ans := IntMin(tt.a, tt.b)
if ans != tt.want {
t.Errorf("got %d, want %d", ans, tt.want)
}
})
}
}
func BenchmarkIntMin(b *testing.B) {
for i := 0; i < b.N; i++ {
IntMin(1, 2)
}
}
And to pass the flag you can use -args
-argsPass the remainder of the command line (everything after -args) to the test binary, uninterpreted and unchanged. Because this flag consumes the remainder of the command line, the package list (if present) must appear before this flag.
Cmd Example:
go test -args -p
Solution 3:[3]
Although this doesn't print during the test, it prints straight after, which is better than not printing at all.
Define an os.File in your test file to write messages to:
var messagesFile *os.File
func messages() *os.File {
if messagesFile == nil {
messagesFile, _ = os.Create("tests.out")
}
return messagesFile
}
os.Create creates a new file if one doesn't exist, otherwise truncates the existing file.
Within your tests, write messages to that file:
messages().WriteString("my message")
Run your tests using go test, then cat the file. In my case, I use make:
test:
go test .
@cat tests.out
Output looks like:
ok <path to tests>
my message
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Chandan |
| Solution 3 |
