介绍不稳定测试缓解工具
这篇文章介绍了一个 新的 Gradle 插件 和构建扫描改进,旨在缓解您的不稳定测试。
不稳定的测试会通过阻塞 CI 管道并导致不必要的故障调查来破坏软件开发周期。不健康的团队通过重新运行构建来维持生计,有时要运行多次才能完成更改。Martin Fowler 对 非确定性测试 有 一些值得一读的尖锐言论。
要消除组织中的这种寄生虫,您必须识别、优先排序并修复不稳定的测试。
缓解不稳定的测试
有一些巧妙的启发式方法可以帮助识别不稳定的测试。您可以运行一些静态分析来证明测试失败在理论上不可能导致给定的测试失败。您可以计算从失败到通过的“翻转”次数,以及某个阈值,超过该阈值,测试将被视为不稳定。
这些启发式方法通常有效,但它们真的很难做到正确。当您的不稳定测试检测方法本身不稳定时,就会出现一个大问题——人们不信任该系统,他们会选择重新运行并忍受模式,直到他们得到想要的结果。
在相同的执行环境中重新运行测试是识别不稳定测试的一种方法,超出了合理的怀疑。难怪如此多的团队和库都采用了这种简单的策略。它甚至直接内置到 Maven Surefire 和 Failsafe 中。
这就是我们开发 Test Retry Gradle 插件 的原因,该插件会重试失败的测试,以减轻测试不稳定性。
新的 Test Retry Gradle 插件
您可以使用此 Gradle 配置来重试测试,并选择在出现不稳定性时使构建失败。
plugins {
id 'org.gradle.test-retry' version '1.0.0'
}
test {
retry {
failOnPassedAfterRetry = true
maxFailures = 42
maxRetries = 1
}
}
plugins {
id("org.gradle.test-retry") version "1.0.0"
}
tasks.test {
retry {
failOnPassedAfterRetry.set(true)
maxFailures.set(42)
maxRetries.set(1)
}
}
此插件有 4 个特别棒的方面。
- 不需要更改测试源代码。这允许对新的不稳定测试进行主动检测!
- 您可以使用
failOnPassedAfterRetry
控制在遇到不稳定性时构建是失败还是通过。这意味着您可以采用此插件来检测不稳定测试,而不会将其静默。 - 您可以使用
maxFailures
阻止在离散数量的测试失败后在测试运行中重试。如果您的构建遇到许多失败,则很可能存在导致许多测试失败的主要问题,重试会浪费资源。 - 测试将在方法级别或更细粒度级别(如果可能)进行重试,无需重新运行整个测试类!
Test Retry Gradle 插件支持的环境
Test Retry 插件开箱即用地支持 Gradle 5.0 及更高版本,并支持以下测试框架。
- JUnit4
- JUnit Platform (JUnit 5)
- Spock
- TestNG
在某些情况下,插件必须重新执行上游测试或下游测试(例如,当使用 @Test(dependsOn = {})
时),以确保不稳定测试依赖于其所依赖的测试状态的正确性。
有关支持的框架和重试机制的更多信息,请参阅 Test Retry Gradle 插件文档。
如何报告不稳定测试
我们选择报告所有不稳定测试的离散执行,以最大限度地提高与现有测试报告和 IDE 的兼容性。因此,不稳定测试报告可能如下所示。
我们正在努力使不稳定性成为您日常使用的更多工具中的第一类测试结果,以澄清报告。 文档 中有更多关于如何在日志、测试报告和流行的 IDE 中报告不稳定测试的详细信息。
好消息是,构建扫描 已经以清晰准确的方式报告了不稳定测试!
构建扫描的易碎测试支持
Gradle 和 Maven 构建扫描现在会在同一个构建中多次执行测试时,如果测试结果既有 PASSED 又有 FAILED(顺序不限),则会将该测试报告为易碎测试。这使得构建扫描可以使用构建内的重试机制(例如 Maven 的 重新运行失败的测试 选项,例如 -Dsurefire.rerunFailingTestsCount=2
或您自定义的重试机制)来报告易碎测试。
识别和静默易碎测试只是治标不治本。很可能存在一些真正的并发或性能问题,导致您的客户遭受损失——您必须分析易碎测试执行情况以修复它们。您可以在我的博客文章中阅读更多关于 分析 Maven 和 Gradle 构建中的易碎测试 的内容。
结论
我们希望新的 Test Retry Gradle 插件 和新的 易碎测试分析功能 能帮助您消除易碎测试。
请在 Twitter 上 告诉我们您的想法。