不稳定的测试 (Flaky tests)¶
“不稳定”(flaky)的测试是指表现出间歇性或偶发性失败、似乎具有非确定性行为的测试。它们有时通过,有时失败,且原因不明。本页面讨论了可以提供帮助的 pytest 功能,以及用于识别、修复或缓解这些问题的其他通用策略。
为什么不稳定的测试是个问题¶
在使用持续集成(CI)服务器时,不稳定的测试尤其麻烦,因为在合并新的代码更改之前,所有测试都必须通过。如果测试结果不是一个可靠的信号(即测试失败意味着代码更改破坏了测试),开发人员可能会对测试结果失去信任,这可能导致忽略真正的失败。这也是浪费时间的一个来源,因为开发人员必须重新运行测试套件并调查虚假的失败。
潜在的根本原因¶
系统状态¶
从广义上讲,不稳定的测试表明测试依赖于某些未得到适当控制的系统状态——测试环境隔离不足。更高级别的测试由于依赖的状态更多,因此更容易变得不稳定。
当并行运行测试套件(例如使用 pytest-xdist)时,有时会出现不稳定的测试。这可能表明测试依赖于测试执行的顺序。
也许是另一个测试在执行后未能清理干净,留下了导致不稳定测试失败的数据。
该不稳定测试依赖于前一个未能清理干净的测试所产生的数据,而在并行运行时,前一个测试并不总是存在。
修改全局状态的测试通常无法并行运行。
过于严格的断言¶
过于严格的断言会导致浮点数比较问题以及计时问题。pytest.approx() 在这里非常有用。
线程安全性¶
pytest 是单线程的,始终在同一个线程中顺序执行其测试,自身从不创建任何线程。
即使对于并行运行测试的插件(例如 pytest-xdist),通常也是通过创建多个进程并分批运行测试来实现的,而不使用多线程。
当然,测试和固件(fixtures)作为其测试工作流程的一部分自行创建线程是可能的(也是常见的)(例如,一个在后台启动服务器线程的固件,或一个执行生产代码的测试),但必须格外小心。
确保最终等待所有创建的线程结束——例如在测试结束时,或在固件的销毁(teardown)阶段。
避免在多个线程中使用 pytest 提供的原语(
pytest.warns(),pytest.raises()等),因为它们不是线程安全的。
如果您的测试套件使用线程并且您看到了不稳定的测试结果,不要排除测试在隐式使用 pytest 本身的全局状态的可能性。
其他通用策略¶
拆分测试套件¶
将单个测试套件拆分为两个(例如单元测试 vs 集成测试)并仅将单元测试套件用作 CI 门禁是常见的做法。这也有助于保持构建时间在可控范围内,因为高级别测试通常较慢。然而,这意味着确实有可能合入破坏构建的代码,因此需要额外警惕监控集成测试结果。
失败时的视频/截图¶
对于 UI 测试,这些对于理解测试失败时 UI 的状态非常重要。pytest-splinter 可以与 pytest-bdd 等插件一起使用,并且可以在测试失败时保存截图,这有助于隔离原因。
删除或重写测试¶
如果其他测试覆盖了该功能,也许可以删除该测试。如果不能,也许可以在更低级别重写它,这将消除不稳定或使其来源更明显。
隔离 (Quarantine)¶
Mark Lapierre 在 2018 年的一篇文章中讨论了隔离测试的优缺点。
失败时重试的 CI 工具¶
Azure Pipelines(Azure 云 CI/CD 工具,前身为 Visual Studio Team Services 或 VSTS)具有识别不稳定测试并重试失败测试的功能。
研究¶
这是一个有限的列表,请提交问题或拉取请求来扩展它!
Gao, Zebao 等,“Making system user interactive tests repeatable: When and what should we control?.” In Software Engineering (ICSE), 2015 IEEE/ACM 37th IEEE International Conference on, vol. 1, pp. 55-65. IEEE, 2015. PDF
Palomba, Fabio, and Andy Zaidman. “Does refactoring of test smells induce fixing flaky tests?.” In Software Maintenance and Evolution (ICSME), 2017 IEEE International Conference on, pp. 1-12. IEEE, 2017. Google Drive 中的 PDF
Bell, Jonathan 等,“DeFlaker: Automatically detecting flaky tests.” In Proceedings of the 2018 International Conference on Software Engineering. 2018. PDF
Dutta, Saikat 等,“Detecting flaky tests in probabilistic and machine learning applications.” In Proceedings of the 29th ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA), pp. 211-224. ACM, 2020. PDF
Habchi, Sarra 等,“What Made This Test Flake? Pinpointing Classes Responsible for Test Flakiness.” In Proceedings of the 38th IEEE International Conference on Software Maintenance and Evolution (ICSME), IEEE, 2022. PDF
Lamprou, Sokrates. “Non-deterministic tests and where to find them: Empirically investigating the relationship between flaky tests and test smells by examining test order dependency.” 本科论文, 林雪平大学, 2022. LIU-IDA/LITH-EX-G–19/056–SE. PDF
Leinen, Fabian 等,“Cost of Flaky Tests in Continuous Integration: An Industrial Case Study.” 慕尼黑工业大学和 CQSE GmbH, 德国慕尼黑, 2023. PDF
资源¶
Eradicating Non-Determinism in Tests 作者 Martin Fowler, 2011
No more flaky tests on the Go team 作者 Pavan Sudarshan, 2012
The Build That Cried Broken: Building Trust in your Continuous Integration Tests 演讲(视频)作者 Angie Jones, SeleniumConf Austin 2017
Test and Code Podcast: Flaky Tests and How to Deal with Them 作者 Brian Okken 和 Anthony Shaw, 2018
微软
How we approach testing VSTS to enable continuous delivery 作者 Brian Harry MS, 2017
Eliminating Flaky Tests 博客和演讲(视频)作者 Munil Shah, 2017
谷歌
Flaky Tests at Google and How We Mitigate Them 作者 John Micco, 2016
Where do Google’s flaky tests come from? 作者 Jeff Listfield, 2017
Dropbox: * Athena: Our automated build health management system 作者 Utsav Shah, 2019 * How To Manage Flaky Tests in your CI Workflows 作者 Li Haoyi, 2025
Uber: * Handling Flaky Unit Tests in Java 作者 Uber Engineering, 2021 * Flaky Tests Overhaul at Uber 作者 Uber Engineering, 2024