古怪的测试

“片状”试验是一种显示间歇性或偶发性故障的试验,似乎具有非确定性行为。有时会过去,有时会失败,原因不明。本页讨论了Pytest特性,这些特性有助于识别、修复或减轻这些特性的其他一般策略。

为什么片状测试是个问题

当使用持续集成(CI)服务器时,片状测试尤其麻烦,因此在合并新的代码更改之前,所有测试都必须通过。如果测试结果不是一个可靠的信号——测试失败意味着代码更改破坏了测试——开发人员可能会对测试结果产生不信任,从而导致忽略真正的失败。这也是浪费时间的原因,因为开发人员必须重新运行测试套件并调查虚假的失败。

潜在根本原因

系统状态

一般来说,一个片状测试表明测试依赖于一些未被适当控制的系统状态——测试环境没有充分隔离。更高级别的测试更可能是脆弱的,因为它们依赖于更多的状态。

当测试套件并行运行时(例如使用pytest xdist),有时会出现片状测试。这表明测试依赖于测试顺序。

  • 也许另一个测试未能在自身之后进行清理,并留下导致片状测试失败的数据。

  • 片状测试依赖于前一个测试的数据,该数据在自身之后不会被清除,并且在并行运行中,前一个测试并不总是存在。

  • 修改全局状态的测试通常不能并行运行。

过于严格的断言

过于严格的断言可能会导致浮点比较和时间问题。 pytest.approx 这里有用。

PyTest-特征

XFAIL严格

pytest.mark.xfail 具有 strict=False 可用于标记测试,使其失败不会导致整个生成中断。这可以被视为手动隔离,永久使用是相当危险的。

PYTEST_CURRENT_TEST

PYTEST_CURRENT_TEST 可能有助于找出“哪个测试卡住了”。看到了吗 PYTEST_CURRENT_TEST 环境变量 了解更多详细信息。

插件

重新运行任何失败的测试可以通过给它们额外的机会来减轻片状测试的负面影响,这样整个构建就不会失败。几个Pytest插件支持这一点:

故意随机测试的插件可以帮助暴露有状态问题的测试:

其他一般策略

拆分测试套件

通常将单个测试套件拆分为两个,例如单元与集成,并且只将单元测试套件用作CI门。这也有助于保持构建时间的可管理性,因为高级别测试往往较慢。但是,这意味着破坏构建的代码有可能被合并,因此需要额外的警惕来监视集成测试结果。

失败时的视频/屏幕截图

对于UI测试,这些对于理解测试失败时UI的状态非常重要。Pytest Spliter可与Pytest BDD和CAN等插件一起使用 save a screenshot on test failure 这有助于找出原因。

删除或重写测试

如果功能被其他测试覆盖,那么可能可以删除该测试。如果没有,也许可以在较低的水平上重写,这样可以去除薄片或使其来源更明显。

检疫

马克·拉皮埃尔讨论了 Pros and Cons of Quarantined Tests 从2018年开始。

失败时重新运行的CI工具

Azure管道(Azure云CI/CD工具,以前称为Visual Studio团队服务或VST)具有以下功能: identify flaky tests 并重新运行失败的测试。

研究

这是一个有限的列表,请提交一个问题或拉请求扩展它!

  • 高、泽宝、梁雅兰、科恩玛拉、梅蒙阿蒂夫和王振民。”使系统用户交互测试可重复:我们应该控制什么时间和什么?“在里面 Software Engineering (ICSE), 2015 IEEE/ACM 37th IEEE International Conference on 第1卷,第55-65页。IEEE,2015。 PDF

  • Palomba、Fabio和Andy Zaidman。”测试气味的重构是否会导致修复片状测试?“在里面 软件维护与发展(ICSME),2017年IEEE国际会议 ,1-12页。IEEE,2017。 PDF in Google Drive

  • Bell、Jonathan、Owolabi Legunsen、Michael Hilton、Lamyaa Eloussi、Tivany Yung和Darko Marinov。”爆燃器:自动检测薄片测试。 2018年国际软件工程会议论文集 . 2018。 PDF

资源