I want to print an informative message to console during a test, but not have the verbose test output.
I have tried printing from the test using:
fmt.Println("my message") // STDOUT
fmt.Fprintln(os.Stderr, "my message") // STDERR
t.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?
CodePudding user response:
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}
CodePudding user response:
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
-args
Pass 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