你正在使用的Go版本是什么( go version
)?
$ go version
go1.16.2 linux/amd6
这个问题在最新版本的发布中是否重现?
是的
你做了什么?
当一个测试二进制文件因某种错误而引发恐慌时,它会以代码2退出(就像所有其他Go二进制文件一样)。然而,go test
隐藏了这个退出代码,总是以代码1退出。我能够从go test
获得除0或1之外的退出代码的唯一方法是引发构建错误。引发恐慌的常见原因有:
- 测试本身由于某种错误而引发恐慌
- 达到
-test.timeout
,并引发恐慌。
在这两种情况下,编译后的测试二进制文件的输出将只包含在恐慌之前运行的测试。没有输出未运行的测试。
任何运行go test -json
并希望尝试重新运行失败的测试(例如:gotestsum --rerun-fails)的程序都需要能够区分这两种情况: - 所有测试都已运行,但某些测试失败 - 退出代码1
- 一些测试未运行,可能是因为恐慌 - (当前退出代码1)
似乎目前无法检测到这两种情况,这使得安全地重新运行单个失败的测试变得不可能。如果运行测试的程序在发生恐慌后尝试重新运行测试,它只会知道已运行的测试,而不是任何未运行的测试。
你期望看到什么?
我希望go test
始终使用编译后的测试二进制文件的退出代码。这样,如果测试二进制文件发生恐慌,go test
将以代码2退出。如果出于某种原因不使用代码2用于此目的,任何非1的退出代码也都可以使用。
5条答案
按热度按时间zpjtge221#
从技术上讲,扫描所有测试输出并在任何行中查找
panic:
前缀是可能的,但这似乎既昂贵又容易出错。我希望使用退出代码是一个更简单、更安全的选择。8qgya5xd2#
https://golang.org/cl/309250提到了这个问题:
cmd/go: use exit code from compiled test binary on error
5lhxktic3#
我想让
go test
始终使用编译后的测试二进制文件的退出代码。我认为这并不合理:通常情况下,go test
可能调用多个二进制文件,那么如果它们返回不同的退出代码该怎么办?tsm1rwdh4#
看起来目前无法检测到[由于之前的恐慌而省略的测试],这使得无法安全地重新运行单个失败的测试。
这似乎是一个合理的担忧,但我认为我们应该更直接地解决它。也许我们可以在输出的末尾注入一个额外的
TestEvent
,以防发生恐慌?或者,也许 #38382 中描述的行为实际上是这里的解决方案:目前看来,您可以通过 JSON 输出中存在具有
"Action":"run"
事件但没有相应事件(如"Action":"pass"
或"Action":"fail"
)的Test
来检测不完整的测试运行。如果测试用例开始但既未通过也未失败,则测试运行必然是不完整的,之后的测试可能丢失。然而,这仍然留下了在运行测试之间、在所有测试完成后但在
TestMain
返回之前或在程序发生恐慌(或调用os.Exit(1)
)之前检测程序的问题。但也许可以通过运行go test -list .
并将其与出现在go test -json
输出中的测试进行比较来检测这种情况。jhkqcmku5#
@bcmills 感谢你的快速回复。
我认为这并不一致:通常情况下,go test可能会调用多个二进制文件,那么如果它们返回不同的退出代码会发生什么呢?
在Go工具链(以及其他软件)中已经有了处理这种情况的明确模式:
go test
使用退出代码1(而不是0)go test
使用退出代码2(而不是0或1)这对我来说似乎是合理的。用户请求执行所有这些测试,如果这个请求没有得到满足(所有测试都没有运行),用退出代码表示似乎很合适。即使某些包确实运行了所有测试也没关系。
这似乎是一个合理的担忧,但我认为我们应该更直接地解决它。也许我们可以让go test在输出的末尾注入一个额外的TestEvent,以防发生恐慌?
我考虑过这一点,但这样做似乎会更加复杂,可能存在更多的错误(因为有很多情况需要处理),并且可能实际上不会比简单的解决方案提供更多的价值。
或者,也许在 #38382 中注意到的行为实际上是这里的解决方案:目前看来,你可以通过JSON输出中包含一个具有"Action":"run"但没有相应事件的Test来检测不完整的测试运行。
#38382 描述了一个异常情况。大多数时候,当一个测试发生恐慌时,它确实会包含一个
"Action":"Fail"
事件。改变这一点将是一个破坏性的更改。例如:这似乎是正确的行为。问题出在不完整的包上,而不是测试。
这仍然留下了在测试之间、在测试之后但在TestMain返回之前以及在所有测试完成后但在go test -json输出之前检测程序发生恐慌(或调用os.Exit(1))的问题。但也许可以通过运行 go test -list . 并将该列表与出现在 go test -json 输出中的测试进行比较来检测到这种情况。
这比简单地不隐藏相关的退出代码要好得多吗?这似乎要复杂得多且容易出错。有很多事情可以改变测试列表、环境变量、构建标签,甚至是命令行参数。
go list
不太可能能够重现正确的测试列表。另外,你能对当前行为是正确的原因进行评论吗?为什么
go test
应该隐藏实际的测试二进制文件的错误代码?