如何在不使用 verbose 选项的情况下,从 go test 打印到控制台?

huangapple go评论108阅读模式
英文:

How to print from go test to console without using verbose option

问题

我想从一个测试中向控制台打印一条信息,但不想看到冗长的测试输出。

我尝试使用以下方法在测试中进行打印:

  • fmt.Println("我的消息") // STDOUT
  • fmt.Fprintln(os.Stderr, "我的消息") // STDERR
  • t.Log("我的消息\n") // testing.T log

这些方法都会在控制台上显示相同的效果,如果使用go test -v命令,则会显示,但如果只使用go test命令,则不会显示。

然而,使用go test -v命令,我还会得到所有冗长的测试输出,例如:

=== RUN   My_Test
--- PASS: My_Test (0.07s)

go help testflag命令说:

-v
    详细输出:记录所有运行的测试。即使测试成功,也打印所有Log和Logf调用的文本。

但是我想要的是记录所有运行的测试,但是仍然打印所有Log和Logf调用的文本。

有没有办法在测试中打印可见的消息,但不看到RUNPASS的消息?

英文:

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") // 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?

答案1

得分: 1

尽管这段代码在测试期间不会打印任何内容,但它会在测试结束后打印出来,这比根本不打印要好。

在你的测试文件中定义一个os.File,用于写入消息:

var messagesFile *os.File

func messages() *os.File {
	if messagesFile == nil {
		messagesFile, _ = os.Create("tests.out")
	}
	return messagesFile
}

os.Create会在文件不存在时创建一个新文件,否则会截断现有文件。

在你的测试中,将消息写入该文件:

messages().WriteString("my message")

使用go test运行你的测试,然后使用cat命令查看文件内容。在我的情况下,我使用make命令:

test:
	go test .
	@cat tests.out

输出如下所示:

ok	<测试路径>
my message
英文:

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(&quot;tests.out&quot;)
	}
	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(&quot;my message&quot;)

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	&lt;path to tests&gt;
my message

答案2

得分: 0

测试框架“劫持”了标准输出和错误流,出于明显的原因。所以无论如何,写入这些流的内容是否出现在输出中都由测试框架控制,并且除了使用“-v”标志显示或隐藏所有内容之外,它没有提供其他“自定义”选项。

你可以使用“-json”测试标志来实现:

-json
    以 JSON 格式记录详细输出和测试结果。这以机器可读的格式呈现与“-v”标志相同的信息。

因此,你可以获得使用“-v”时会得到的所有输出,但是每行都有一个单独的 JSON 对象。

有了这个测试函数:

func TestMy_Test(t *testing.T) {
	fmt.Println("[custom] my message from fmt.Println")
}

运行 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

运行 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}

你可以编写一个简单的应用程序来处理和过滤这些 JSON 对象。或者你可以像过滤其他任何输出一样过滤输出。

运行 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"}

如果你还想要“pass”或“fail”消息,运行 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}
英文:

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(&quot;[custom] my message from fmt.Println&quot;)
}

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 .

{&quot;Time&quot;:&quot;2022-05-10T09:26:26.712800797+02:00&quot;,&quot;Action&quot;:&quot;run&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.71293072+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Output&quot;:&quot;=== RUN   TestMy_Test\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.712946548+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Output&quot;:&quot;[custom] my message from fmt.Println\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.712954637+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Output&quot;:&quot;--- PASS: TestMy_Test (0.00s)\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.712958774+02:00&quot;,&quot;Action&quot;:&quot;pass&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Elapsed&quot;:0}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.712964812+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Output&quot;:&quot;PASS\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.713170439+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Output&quot;:&quot;ok  \tgithub.com/icza/play\t0.002s\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:26:26.713573313+02:00&quot;,&quot;Action&quot;:&quot;pass&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Elapsed&quot;: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 &#39;\[custom\]&#39;

{&quot;Time&quot;:&quot;2022-05-10T09:28:24.197077681+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Output&quot;:&quot;[custom] my message from fmt.Println\n&quot;}

If you also want the "pass" or "fail" messages, run go test -json . |grep &#39;&quot;pass&quot;\|&quot;fail&quot;\|\[custom\]&#39;

{&quot;Time&quot;:&quot;2022-05-10T09:29:26.069181336+02:00&quot;,&quot;Action&quot;:&quot;output&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Output&quot;:&quot;[custom] my message from fmt.Println\n&quot;}
{&quot;Time&quot;:&quot;2022-05-10T09:29:26.069189228+02:00&quot;,&quot;Action&quot;:&quot;pass&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Test&quot;:&quot;TestMy_Test&quot;,&quot;Elapsed&quot;:0}
{&quot;Time&quot;:&quot;2022-05-10T09:29:26.069199239+02:00&quot;,&quot;Action&quot;:&quot;pass&quot;,&quot;Package&quot;:&quot;github.com/icza/play&quot;,&quot;Elapsed&quot;:0}

答案3

得分: 0

你可以创建自己的日志函数并用它在屏幕上打印输出。

func Log(args ...interface{}) {
    fmt.Fprintln(os.Stdout, args...)
}

你还可以根据传递的标志条件来打印日志。

var p = flag.Bool("p", false, "Enable Local Logging")

func MyLog(args ...interface{}) {
  if *p {
    fmt.Fprintln(os.Stdout, args...)
  }
}

示例

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

要传递标志,你可以使用-args

-args 将命令行的剩余部分(-args 后面的所有内容)传递给测试二进制文件,未经解释和更改。由于此标志会消耗命令行的剩余部分,因此包列表(如果存在)必须出现在此标志之前。

命令示例:

go test -args -p
英文:

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(&quot;p&quot;, false, &quot;Enable Local Logging&quot;)

func MyLog(args ...interface{}) {
  if *p {
    fmt.Fprintln(os.Stdout, args...)
  }
}

Example

package main

import (
    &quot;fmt&quot;
    &quot;testing&quot;
    &quot;os&quot;
    &quot;flag&quot;
)

var p = flag.Bool(&quot;p&quot;, false, &quot;Enable Local Logging&quot;)

func Log(args ...interface{}) {
  if *p {
    fmt.Fprintln(os.Stdout, args...)
  }
}

func IntMin(a, b int) int {
    if a &lt; b {
        return a
    }
    return b
}

func TestIntMinBasic(t *testing.T) {
    ans := IntMin(2, -2)
    if ans != -2 {
        t.Errorf(&quot;IntMin(2, -2) = %d; want -2&quot;, 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(&quot;Print to Screen&quot;)

    for _, tt := range tests {

        testname := fmt.Sprintf(&quot;%d,%d&quot;, tt.a, tt.b)
        t.Run(testname, func(t *testing.T) {
            ans := IntMin(tt.a, tt.b)
            if ans != tt.want {
                t.Errorf(&quot;got %d, want %d&quot;, ans, tt.want)
            }
        })
    }
}

func BenchmarkIntMin(b *testing.B) {
    for i := 0; i &lt; 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

huangapple
  • 本文由 发表于 2022年5月10日 08:10:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/72179412.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定