Go Wiki:测试失败

如果您注意到 Go 项目中的测试失败,应该怎么做?

测试目标

为 Go 包编写(和运行)测试的目标是了解该包及其依赖项的行为。

Go 包的测试失败可能会提供有关以下信息:

  • 包或其依赖项中的实现缺陷,
  • 对包 API 的错误假设,
  • 测试本身的错误(例如,有关时序的无效假设),
  • 出乎意料的高资源需求(例如,内存或 CPU 时间),或
  • 底层平台中的错误或测试基础设施中的缺陷(可能需要升级或规避)。

在某些情况下,测试失败的原因可能不清楚:它可能由上述条件中的*一个以上*引起。 就像重复一项科学实验一样,让测试多次失败有时可以从特定的失败模式中提供更多信息。

但是,如果测试失败但没有提供任何新信息,那么该测试就没有实现其目的。

查找测试失败

测试失败通常从以下途径注意到:

  • Go 构建仪表板,尤其是在构建器分类期间;
  • 待定更改上的 TryBot 或 SlowBot 失败;
  • 在特定包或包上运行 go test,无论是处理 Go 项目存储库中的工作,还是作为用户自己模块中的 (例如) go test all 的一部分;
  • 或在从源代码安装或测试贡献的更改时运行 all.bashall.bat

对测试失败进行分类

一旦注意到失败,我们就需要对其进行*分类*。 分类的目标是确定:

  1. 失败提供的信息是新的吗?
  2. 谁最适合分析来自失败的新信息?

识别新信息

首先搜索*开放式问题*,查找失败的关键详细信息,例如失败测试的名称和/或错误文本的其他独特片段(例如,错误代码)。

如果您找到现有问题,请首先检查问题讨论,看看是否已修复该失败,并且您的失败信息是否提供了相关的​​新信息。 如果是这样,请*在问题上发表评论*并附上详细信息:

  • 描述您正在测试的 Go 版本 (go version)
  • 如何以及在哪里运行测试,例如:
    • go env 输出
    • 您的机器和操作系统配置
    • 您的网络配置和状态
  • 您是否能够重现失败以及重现的频率。

理想情况下,附加或链接到完整的测试日志(可能放在 <details> 块中)。

如果您找不到现有问题,请提交一个新问题。

提交问题

粘贴足够的测试日志,以便将来的报告者能够搜索到该问题,包括测试的名称及其日志输出中的任何独特部分。(如果测试日志很长 — 例如,如果它包含大型 goroutine 转储 — 考虑发布较短的摘录和/或将完整的失败消息包含在 <details> 块中。)

您可以使用 fetchlogsgreplogs 工具来搜索构建仪表板中类似的失败。

# 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 上的近期历史记录,以及/或升级给能帮助识别相关所有者的人 — 并考虑使用您学到的知识更新所有者表!)

如果失败似乎特定于 GOOSGOARCH,请用相应的 GOOS 和/或 GOARCH 标签标记问题,并在问题中提及 @golang/port-maintainers 的相关子团队。

如果失败似乎影响了至少一个*一流端口*,请将问题添加到当前发布里程碑,并标记为 release-blocker。否则,将问题添加到 Backlog 里程碑。

如果失败似乎特定于某个构建器(例如,网络连接问题或需要系统更新的平台错误),请查阅 x/build/dashboard/builders.go 查找该构建器的维护者,并在问题中提及他们。(对于没有明确列出维护者的构建器,请提及 @golang/release 团队。)

处理测试失败

一旦为测试失败提交了问题,相关的包、端口和/或构建器维护者应检查从测试失败中获得的​​信息,并通过以下一项或多项操作来决定如何*处理*它:

  • 撤销对被认为引入问题的代码或测试基础设施的更改,
  • 修复(或应用变通方法)失败的根本原因,
  • 收集更多信息,通过订阅问题更新和/或运行更多测试,
  • 报告底层依赖项、平台或测试基础设施中的缺陷,以及/或
  • 降低失败的优先级,通过在受影响的平台上跳过失败(或将这些平台标记为已损坏),然后将问题移至未来的或 Backlog 里程碑,以及/或删除 release-blocker 标签。

当维护者决定降低测试失败的优先级时,他们会确定*该测试的其他失败将不会提供有用的新信息*。 此时,测试不再履行其目的,维护者应抑制失败 — 通常通过添加对 testenv.SkipFlakyt.Skipf 的调用。

跳过测试失败

当我们添加对 testenv.SkipFlaky 的调用时,我们的目标是消除不提供新信息的失败模式,同时尽可能保留测试的价值。

  • 如果观察到的失败只是测试的几种可能失败模式之一,则仅为该失败模式跳过测试。

    • 例如,如果错误始终是特定的,如 syscall.ECONNRESET,请使用 errors.Is 检查该特定错误。
  • 如果认为失败会影响特定 GOOS 和/或 GOARCH 的所有版本,或者无法确定受影响的版本,请根据 runtime.GOOS 和/或 runtime.GOARCH 进行检查,并仅跳过受影响的平台。

  • 如果失败是由于*特定版本*的平台上的错误,请根据 testenv.BuilderGO_BUILDER_NAME 环境变量跳过测试。(如果测试对外部 Go 用户失败,他们可以选择升级到不受影响的平台版本 — 他们很可能应该看到测试失败以了解该错误的存在!)

    • 还应考虑添加另一个环境变量,用户和贡献者可以设置该变量来确认错误并抑制失败。

将构建器或端口标记为已损坏

平台错误或核心包(如 osnetruntime)中的错误可能会影响如此多的测试,以至于无法跳过失败,或者可能会表现为编译或链接时失败。 如果发生此类错误,选项将更加有限:如果我们无法撤销更改或修复或规避根本原因,并且不需要收集更多信息,我们只能通过将*整个构建器或平台*标记为已损坏来降低失败的优先级。

要将构建器标记为已损坏,请在其 x/build/dashboard/builders.go 配置中进行编辑,在 KnownIssue 字段中添加一个问题;请注意,已知问题构建器通常会在仪表板分类期间被跳过。

一流端口的损坏构建器应将其已知问题标记为 release-blocker,等待决定是修复构建器还是放弃对受影响平台版本的支持。

如果次要端口的所有构建器都已损坏,则该端口本身可能被视为已损坏。 讨论 #53060 旨在解决如何处理已损坏的次要端口的问题。


此内容是 Go Wiki 的一部分。