不稳定的测试¶
“不稳定”测试是指表现出间歇性或偶发性失败,似乎具有非确定性行为的测试。有时它通过,有时它失败,而且原因不明。本页面讨论了可以提供帮助的 pytest 功能以及用于识别、修复或缓解这些问题的一般策略。
为什么不稳定的测试是个问题¶
当使用持续集成 (CI) 服务器时,不稳定的测试尤其麻烦,因为在合并新的代码更改之前,所有测试都必须通过。如果测试结果不是可靠的信号——即测试失败意味着代码更改破坏了测试——开发人员可能会不信任测试结果,这可能导致忽视真正的失败。这也是浪费时间的一个来源,因为开发人员必须重新运行测试套件并调查虚假失败。
潜在根本原因¶
系统状态¶
广义而言,不稳定的测试表明测试依赖于一些未被适当控制的系统状态——测试环境未充分隔离。更高级别的测试由于依赖更多的状态,因此更容易不稳定。
当测试套件并行运行时(例如使用 pytest-xdist),有时会出现不稳定的测试。这可能表明测试依赖于测试顺序。
也许是另一个测试未能清理自身,留下了导致不稳定测试失败的数据。
不稳定的测试依赖于上一个测试的数据,而上一个测试没有清理自身,并且在并行运行中,上一个测试并不总是存在。
修改全局状态的测试通常不能并行运行。
断言过于严格¶
过于严格的断言可能会导致浮点比较和时间问题。pytest.approx() 在这里很有用。
线程安全¶
pytest 是单线程的,它始终在同一个线程中顺序执行测试,从不自行生成任何线程。
即使是并行运行测试的插件,例如 pytest-xdist,通常也是通过生成多个进程并分批运行测试来工作的,而不是使用多个线程。
当然,测试和夹具作为其测试工作流程的一部分(例如,一个在后台启动服务器线程的夹具,或者一个执行生成线程的生产代码的测试)自行生成线程是可能的(也很常见),但必须小心
确保最终等待所有生成的线程——例如在测试结束时,或者在夹具的拆卸过程中。
避免从多个线程使用 pytest 提供的原语(
pytest.warns()、pytest.raises()等),因为它们不是线程安全的。
如果您的测试套件使用线程并且您看到了不稳定的测试结果,请不要排除测试隐式使用了 pytest 自身全局状态的可能性。
其他一般策略¶
拆分测试套件¶
将单个测试套件拆分为两个(例如单元测试与集成测试),并仅使用单元测试套件作为 CI 门槛是很常见的。这也有助于控制构建时间,因为高级别测试往往较慢。然而,这意味着可能合并会破坏构建的代码,因此需要额外警惕地监控集成测试结果。
失败时录制视频/截图¶
对于 UI 测试,这些对于理解测试失败时 UI 的状态很重要。pytest-splinter 可以与 pytest-bdd 等插件一起使用,并且可以在 测试失败时保存屏幕截图,这有助于隔离原因。
删除或重写测试¶
如果功能已被其他测试覆盖,则可以删除该测试。如果没有,也许可以在更低的级别重写它,这将消除不稳定性或使其来源更明显。
隔离¶
Mark Lapierre 在 2018 年的一篇文章中讨论了 隔离测试的利弊。
失败时重试的 CI 工具¶
Azure Pipelines(Azure 云 CI/CD 工具,前身为 Visual Studio Team Services 或 VSTS)具有识别不稳定测试并重新运行失败测试的功能。
研究¶
这是一个有限的列表,请提交问题或拉取请求以扩展它!
Gao, Zebao, Yalan Liang, Myra B. Cohen, Atif M. Memon, and Zhen Wang。“使系统用户交互测试可重复:我们何时以及应该控制什么?”。在 Software Engineering (ICSE), 2015 IEEE/ACM 37th IEEE International Conference on, vol. 1, pp. 55-65. IEEE, 2015. PDF
Palomba, Fabio, and Andy Zaidman。“测试异味的重构是否能修复不稳定测试?”。在 Software Maintenance and Evolution (ICSME), 2017 IEEE International Conference on, pp. 1-12. IEEE, 2017. Google Drive 中的 PDF
Bell, Jonathan, Owolabi Legunsen, Michael Hilton, Lamyaa Eloussi, Tifany Yung, and Darko Marinov。“DeFlaker:自动检测不稳定测试。”。在 Proceedings of the 2018 International Conference on Software Engineering. 2018. PDF
Dutta, Saikat 和 Shi, August 和 Choudhary, Rutvik 和 Zhang, Zhekun 和 Jain, Aryaman 和 Misailovic, Sasa。“在概率和机器学习应用中检测不稳定测试。”。在 Proceedings of the 29th ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA), pp. 211-224. ACM, 2020. PDF
Habchi, Sarra 和 Haben, Guillaume 和 Sohn, Jeongju 和 Franci, Adriano 和 Papadakis, Mike 和 Cordy, Maxime 和 Le Traon, Yves。“是什么让这个测试不稳定?找出导致测试不稳定的类。”。在 Proceedings of the 38th IEEE International Conference on Software Maintenance and Evolution (ICSME), IEEE, 2022. PDF
Lamprou, Sokrates。“非确定性测试以及在哪里找到它们:通过检查测试顺序依赖性来实证研究不稳定测试与测试异味之间的关系。”。学士论文,林雪平大学计算机与信息科学系,2022。LIU-IDA/LITH-EX-G–19/056–SE。 PDF
Leinen, Fabian 和 Elsner, Daniel 和 Pretschner, Alexander 和 Stahlbauer, Andreas 和 Sailer, Michael 和 Jürgens, Elmar。“持续集成中不稳定测试的成本:一项工业案例研究。”。慕尼黑工业大学和 CQSE GmbH,德国慕尼黑,2023。 PDF
资源¶
消除测试中的非确定性,作者 Martin Fowler,2011
Go 团队不再有不稳定的测试,作者 Pavan Sudarshan,2012
“构建失败哭泣:在持续集成测试中建立信任” 演讲(视频),作者 Angie Jones,在 SeleniumConf Austin 2017
测试与代码播客:不稳定的测试以及如何处理它们,作者 Brian Okken 和 Anthony Shaw,2018
微软
我们如何测试 VSTS 以实现持续交付,作者 Brian Harry MS,2017
消除不稳定测试 博客和演讲(视频),作者 Munil Shah,2017
谷歌
谷歌的不稳定测试以及我们如何缓解它们,作者 John Micco,2016
谷歌的不稳定测试从何而来?,作者 Jeff Listfield,2017
Dropbox: * Athena:我们的自动化构建健康管理系统,作者 Utsav Shah,2019 * 如何在 CI 工作流中管理不稳定测试,作者 Li Haoyi,2025
优步: * 在 Java 中处理不稳定的单元测试,作者优步工程团队,2021 * 优步不稳定测试大修,作者优步工程团队,2024