测试:如果将标准输出重定向,则go test JSON输出报告失败,

wkftcu5l  于 4个月前  发布在  Go
关注(0)|答案(3)|浏览(47)

你正在使用的Go版本是什么(go version)?

$ go version
go version go1.13.4 darwin/amd64

这个问题在最新的发布版本中是否重现?
应该会;我觉得没有理由不会,因为我高亮的代码在主分支上。

你正在使用什么操作系统和处理器架构(go env)?
go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/jamesjohnston/Library/Caches/go-build"
GOENV="/Users/jamesjohnston/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/jamesjohnston/Thumbtack/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.13.4/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.13.4/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS="-I/usr/local/include"
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-L/usr/local/lib"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/4_/s_mp89t54_b8xbgwclmf2scw0000gp/T/go-build586602208=/tmp/go-build -gno-record-gcc-switches -fno-common"

你做了什么?
创建一个覆盖os.Stdout的测试,然后使用go test -json运行它。
https://play.golang.org/p/zeonvI5FdUJ

func TestWithOverride(t *testing.T) {
	_, stdOutPipe, _ := os.Pipe()
	os.Stdout = stdOutPipe
}

然后使用go test -json运行测试。

你期望看到什么?
这个测试应该成功:退出代码都应该是0,JSON输出应该表明测试成功。

你看到了什么?
JSON输出表明测试失败,但退出代码仍然是0,表示成功:

jamesjohnston-mac:testcase jamesjohnston$ go test -json
{"Time":"2020-02-19T15:27:30.928348-08:00","Action":"run","Package":"github.com/thumbtack/go/testcase","Test":"TestWithOverride"}
{"Time":"2020-02-19T15:27:30.928623-08:00","Action":"output","Package":"github.com/thumbtack/go/testcase","Test":"TestWithOverride","Output":"=== RUN   TestWithOverride\n"}
{"Time":"2020-02-19T15:27:30.928661-08:00","Action":"output","Package":"github.com/thumbtack/go/testcase","Test":"TestWithOverride","Output":"--- PASS: TestWithOverride (0.00s)\n"}
{"Time":"2020-02-19T15:27:30.92872-08:00","Action":"output","Package":"github.com/thumbtack/go/testcase","Test":"TestWithOverride","Output":"ok  \tgithub.com/thumbtack/go/testcase\t0.006s\n"}
{"Time":"2020-02-19T15:27:30.928732-08:00","Action":"fail","Package":"github.com/thumbtack/go/testcase","Test":"TestWithOverride","Elapsed":0.007}
jamesjohnston-mac:testcase jamesjohnston$ echo $?
0

请注意在JSON中报告的失败:"Action":"fail"。这非常模糊:测试是通过还是失败了?退出代码说了一个,但JSON输出说另一个。

进一步调查
注意,如果我们运行上面的play链接,我们得到这样的输出:

=== RUN   TestWithOverride
--- PASS: TestWithOverride (0.00s)

All tests passed.

然而,如果我们写一个“正常”的测试,不篡改Stdout,我们会得到额外的输出:最后的“PASS”: https://play.golang.org/p/3Z8hY3rAfhj

package main

import (
	"testing"
)

func TestWithoutOverride(t *testing.T) {
	// do nothing
}

输出:

=== RUN   TestWithoutOverride
--- PASS: TestWithoutOverride (0.00s)
PASS

All tests passed.

看起来test2json将缺乏最终的“PASS”解释为转换为JSON时的失败。然而,主要的“go test”命令并没有这样做,因此以“成功”的退出代码退出。因此,我们最终得到了一个同时“通过”和“失败”的测试。
问题似乎是:testing.go文件完全被写入,假设终端用户永远不会写入任何os.StdXYZ变量。例如:
go/src/testing/testing.go
第1211行 in c4c73ce
| | fmt.Println("PASS") |

fmt.Println("PASS")

是写入最终“PASS”注解的代码。
几个可能的修复方法可能是:

  • 更新testing.go,使其在测试开始时读取os.StdXYZ变量,然后再从它们中读取一次。例如,上面的代码可以更新为 fmt.Fprintln(originalStdOut, "PASS") 。这可以保护代码免受篡改标准文件的测试的影响。
  • 更新go test和/或test2json,使得如果由于这个问题(或其他任何原因)测试二进制输出被截断,它将一致地通过或失败测试,并且不会在JSON和退出代码之间留下分歧。

有趣的是,这个问题仅限于-json标志。如果我们在不使用该标志的情况下运行go test,测试将通过且不会有任何出错的迹象。

理由/背景
这个测试用例是从我老板那里编写的一个测试中衍生出来的。它暂时替换了Stdout,以便捕获并与预期输出进行比较。问题是,对于一个测试来说,这个人忘记了恢复原始Stdout,直到我开始引入使用JSON输出的工作工具,如使用 gotestsum 将JSON转换为JUnit XML,然后将其传递给Jenkins JUnit插件......Jenkins令人惊讶地报告了失败的测试,尽管测试套件“通过了”。
虽然用os.Stdout替换可能不是测试命令行工具的最佳方法,但有人确实写了这样一个测试,在这种场景下,我认为当面对像这样的“有趣”测试时,测试运行器应该表现出可预测的行为。

uyto3xhc

uyto3xhc2#

虽然用 os.Stdout 替换可能不是测试命令行工具的最佳方法,但确实有人用这种方式编写了测试。在这种情况下,我认为当遇到像这样的“有趣”测试时,测试运行器应该表现出可预测的行为。
我绝对同意你不应该像那样替换 os.Stdout。类似的问题是调用 os.Exit(0) 如何使整个包 pass its tests 在它绝对不应该的情况下发生。
我不知道我们能在这里做什么,但我认为将 go test -json 适应这样的测试并不是一个好主意。

mbjcgjjk

mbjcgjjk3#

testing 包本身可以在每次测试结束时保存 os.Stdoutos.Stderr 并恢复它们。任何试图重新分配这些资源的并行测试都会被报告为竞争,但无论如何这似乎都是一个好消息。

相关问题