Go Wiki:测试失败
如果您注意到 Go 项目中的测试失败,应该怎么做?
测试目标
为 Go 包编写(和运行)测试的目标是了解该包及其依赖项的行为。
Go 包的测试失败可能会提供有关以下信息:
- 包或其依赖项中的实现缺陷,
- 对包 API 的错误假设,
- 测试本身的错误(例如,有关时序的无效假设),
- 出乎意料的高资源需求(例如,内存或 CPU 时间),或
- 底层平台中的错误或测试基础设施中的缺陷(可能需要升级或规避)。
在某些情况下,测试失败的原因可能不清楚:它可能由上述条件中的*一个以上*引起。 就像重复一项科学实验一样,让测试多次失败有时可以从特定的失败模式中提供更多信息。
但是,如果测试失败但没有提供任何新信息,那么该测试就没有实现其目的。
查找测试失败
测试失败通常从以下途径注意到:
- Go 构建仪表板,尤其是在构建器分类期间;
- 待定更改上的 TryBot 或 SlowBot 失败;
- 在特定包或包上运行
go test
,无论是处理 Go 项目存储库中的工作,还是作为用户自己模块中的 (例如)go test all
的一部分; - 或在从源代码安装或测试贡献的更改时运行
all.bash
或all.bat
。
对测试失败进行分类
一旦注意到失败,我们就需要对其进行*分类*。 分类的目标是确定:
- 失败提供的信息是新的吗?
- 谁最适合分析来自失败的新信息?
识别新信息
首先搜索*开放式问题*,查找失败的关键详细信息,例如失败测试的名称和/或错误文本的其他独特片段(例如,错误代码)。
如果您找到现有问题,请首先检查问题讨论,看看是否已修复该失败,并且您的失败信息是否提供了相关的新信息。 如果是这样,请*在问题上发表评论*并附上详细信息:
- 描述您正在测试的 Go 版本 (
go version
) - 如何以及在哪里运行测试,例如:
go env
输出- 您的机器和操作系统配置
- 您的网络配置和状态
- 您是否能够重现失败以及重现的频率。
理想情况下,附加或链接到完整的测试日志(可能放在 <details>
块中)。
如果您找不到现有问题,请提交一个新问题。
提交问题
粘贴足够的测试日志,以便将来的报告者能够搜索到该问题,包括测试的名称及其日志输出中的任何独特部分。(如果测试日志很长 — 例如,如果它包含大型 goroutine 转储 — 考虑发布较短的摘录和/或将完整的失败消息包含在 <details>
块中。)
您可以使用 fetchlogs
和 greplogs
工具来搜索构建仪表板中类似的失败。
# download recent logs
fetchlogs -n 1024 -repo all
# search logs for some regexp describing the failure message
greplogs -l -e $FAILURE_REGEXP
如果失败似乎特定于某个包,请查阅 https://dev.golang.org/owners 查找该包的维护者,并在问题中提及他们。(如果包未列出所有者,请检查该包在 https://cs.opensource.google/go 上的近期历史记录,以及/或升级给能帮助识别相关所有者的人 — 并考虑使用您学到的知识更新所有者表!)
如果失败似乎特定于 GOOS
或 GOARCH
,请用相应的 GOOS 和/或 GOARCH 标签标记问题,并在问题中提及 @golang/port-maintainers 的相关子团队。
如果失败似乎影响了至少一个*一流端口*,请将问题添加到当前发布里程碑,并标记为 release-blocker
。否则,将问题添加到 Backlog
里程碑。
如果失败似乎特定于某个构建器(例如,网络连接问题或需要系统更新的平台错误),请查阅 x/build/dashboard/builders.go
查找该构建器的维护者,并在问题中提及他们。(对于没有明确列出维护者的构建器,请提及 @golang/release 团队。)
处理测试失败
一旦为测试失败提交了问题,相关的包、端口和/或构建器维护者应检查从测试失败中获得的信息,并通过以下一项或多项操作来决定如何*处理*它:
- 撤销对被认为引入问题的代码或测试基础设施的更改,
- 修复(或应用变通方法)失败的根本原因,
- 收集更多信息,通过订阅问题更新和/或运行更多测试,
- 报告底层依赖项、平台或测试基础设施中的缺陷,以及/或
- 降低失败的优先级,通过在受影响的平台上跳过失败(或将这些平台标记为已损坏),然后将问题移至未来的或
Backlog
里程碑,以及/或删除release-blocker
标签。
当维护者决定降低测试失败的优先级时,他们会确定*该测试的其他失败将不会提供有用的新信息*。 此时,测试不再履行其目的,维护者应抑制失败 — 通常通过添加对 testenv.SkipFlaky
或 t.Skipf
的调用。
跳过测试失败
当我们添加对 testenv.SkipFlaky
的调用时,我们的目标是消除不提供新信息的失败模式,同时尽可能保留测试的价值。
-
如果观察到的失败只是测试的几种可能失败模式之一,则仅为该失败模式跳过测试。
- 例如,如果错误始终是特定的,如
syscall.ECONNRESET
,请使用errors.Is
检查该特定错误。
- 例如,如果错误始终是特定的,如
-
如果认为失败会影响特定
GOOS
和/或GOARCH
的所有版本,或者无法确定受影响的版本,请根据runtime.GOOS
和/或runtime.GOARCH
进行检查,并仅跳过受影响的平台。 -
如果失败是由于*特定版本*的平台上的错误,请根据
testenv.Builder
或GO_BUILDER_NAME
环境变量跳过测试。(如果测试对外部 Go 用户失败,他们可以选择升级到不受影响的平台版本 — 他们很可能应该看到测试失败以了解该错误的存在!)- 还应考虑添加另一个环境变量,用户和贡献者可以设置该变量来确认错误并抑制失败。
将构建器或端口标记为已损坏
平台错误或核心包(如 os
、net
或 runtime
)中的错误可能会影响如此多的测试,以至于无法跳过失败,或者可能会表现为编译或链接时失败。 如果发生此类错误,选项将更加有限:如果我们无法撤销更改或修复或规避根本原因,并且不需要收集更多信息,我们只能通过将*整个构建器或平台*标记为已损坏来降低失败的优先级。
要将构建器标记为已损坏,请在其 x/build/dashboard/builders.go
配置中进行编辑,在 KnownIssue
字段中添加一个问题;请注意,已知问题构建器通常会在仪表板分类期间被跳过。
一流端口的损坏构建器应将其已知问题标记为 release-blocker
,等待决定是修复构建器还是放弃对受影响平台版本的支持。
如果次要端口的所有构建器都已损坏,则该端口本身可能被视为已损坏。 讨论 #53060 旨在解决如何处理已损坏的次要端口的问题。
此内容是 Go Wiki 的一部分。