不稳定的测试

“不稳定”的测试是指表现出间歇性或零星失败的测试,看起来具有非确定性行为。有时它通过,有时它失败,而且原因尚不清楚。此页面讨论了可以提供帮助的 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. “使系统用户交互测试可重复:我们应该何时以及控制什么?。” 在软件工程 (ICSE), 2015 IEEE/ACM 第 37 届 IEEE 国际会议, 第 1 卷, pp. 55-65. IEEE, 2015. PDF

  • Palomba, Fabio, 和 Andy Zaidman. “重构测试异味是否会导致修复不稳定的测试?。” 在软件维护和演化 (ICSME), 2017 IEEE 国际会议, pp. 1-12. IEEE, 2017. Google Drive 中的 PDF

  • Bell, Jonathan, Owolabi Legunsen, Michael Hilton, Lamyaa Eloussi, Tifany Yung, 和 Darko Marinov. “DeFlaker:自动检测不稳定的测试。” 在2018 年国际软件工程会议论文集. 2018. PDF

  • Dutta, Saikat 和 Shi, August 和 Choudhary, Rutvik 和 Zhang, Zhekun 和 Jain, Aryaman 和 Misailovic, Sasa. “在概率和机器学习应用程序中检测不稳定的测试。” 在第 29 届 ACM SIGSOFT 国际软件测试与分析研讨会 (ISSTA) 论文集, pp. 211-224. ACM, 2020. PDF

  • Habchi, Sarra 和 Haben, Guillaume 和 Sohn, Jeongju 和 Franci, Adriano 和 Papadakis, Mike 和 Cordy, Maxime 和 Le Traon, Yves. “是什么让这个测试不稳定?查明负责测试不稳定性的类。” 在第 38 届 IEEE 国际软件维护与演化会议 (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

资源