不稳定的测试¶
“不稳定的”测试是指那些表现出间歇性或偶发性失败,似乎具有非确定性行为的测试。有时它通过,有时它失败,而且原因不明。本页讨论了 pytest 中可以提供帮助的功能以及识别、修复或缓解这些问题的其他通用策略。
为什么不稳定的测试是个问题¶
当使用持续集成 (CI) 服务器时,不稳定的测试尤其麻烦,因为在合并新的代码更改之前,所有测试都必须通过。如果测试结果不是一个可靠的信号——即测试失败意味着代码更改破坏了测试——开发者可能会对测试结果产生不信任,这可能导致忽视真正的失败。这也是浪费时间的来源,因为开发者必须重新运行测试套件并调查虚假的失败。
潜在的根本原因¶
系统状态¶
广义地说,不稳定的测试表明测试依赖于未被适当控制的某些系统状态——测试环境没有充分隔离。高级别的测试更容易不稳定,因为它们依赖更多的状态。
当测试套件并行运行(例如使用 pytest-xdist)时,有时会出现不稳定的测试。这可能表明测试依赖于测试顺序。
也许不同的测试在运行后未能清理自身,留下了导致不稳定测试失败的数据。
不稳定的测试依赖于先前测试的数据,而该先前测试在运行后未能清理自身,并且在并行运行中,该先前测试并非总是存在。
修改全局状态的测试通常无法并行运行。
过于严格的断言¶
过于严格的断言可能导致浮点比较问题以及时间问题。pytest.approx()
在这里很有用。
线程安全¶
pytest 是单线程的,始终在同一个线程中顺序执行其测试,从不自行生成任何线程。
即使是并行运行测试的插件,例如 pytest-xdist,通常也是通过生成多个 进程 并分批运行测试来工作,而不是使用多线程。
当然,测试和 fixtures 可以在其测试工作流程中自行生成线程(例如,在后台启动服务器线程的 fixture,或执行生成线程的生产代码的测试),这是可能且常见的,但必须小心。
确保最终等待任何生成的线程——例如在测试结束时,或在 fixture 的拆卸期间。
避免从多个线程使用 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 和 Zhen Wang。“使系统用户交互测试可重复:我们何时以及应该控制什么?”。载于 Software Engineering (ICSE), 2015 IEEE/ACM 37th IEEE International Conference on, 第 1 卷, 第 55-65 页。IEEE, 2015。PDF
Palomba, Fabio 和 Andy Zaidman。“测试异味重构是否能修复不稳定测试?”。载于 Software Maintenance and Evolution (ICSME), 2017 IEEE International Conference on, 第 1-12 页。IEEE, 2017。Google Drive 中的 PDF
Bell, Jonathan, Owolabi Legunsen, Michael Hilton, Lamyaa Eloussi, Tifany Yung 和 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), 第 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 有限公司,慕尼黑,德国,2023。PDF
资源¶
Martin Fowler, 2011 年文章 《消除测试中的非确定性》
Pavan Sudarshan, 2012 年文章 《Go 团队不再有不稳定测试》
《哭泣的构建:在持续集成测试中建立信任》 讲座(视频)由 Angie Jones 在 2017 年 SeleniumConf Austin 上发表
Brian Okken 和 Anthony Shaw, 2018 年播客 《测试与代码播客:不稳定的测试以及如何处理它们》
微软
Brian Harry MS, 2017 年文章 《我们如何测试 VSTS 以实现持续交付》
Munil Shah, 2017 年博客和讲座(视频)《消除不稳定测试》
谷歌
John Micco, 2016 年文章 《谷歌的不稳定测试以及我们如何缓解它们》
Jeff Listfield, 2017 年文章 《谷歌的不稳定测试从何而来?》
Dropbox: * Utsav Shah, 2019 年文章 《Athena:我们的自动化构建健康管理系统》 * Li Haoyi, 2025 年文章 《如何在 CI 工作流程中管理不稳定测试》
Uber: * Uber Engineering, 2021 年文章 《在 Java 中处理不稳定的单元测试》 * Uber Engineering, 2024 年文章 《Uber 不稳定测试大修》