Python+ Flask实现Mock Server详情
315
2022-08-28
pytest之Flaky Tests(pytest-ignore-flaky)(pytest 类)
一、什么是Flaky Tests?
①Flaky Tests作为一个软件工程术语,目前还缺乏适当的中文翻译。“Flaky”这个单词在英文中的意思是“薄而易剥落的”。倘若据此来解释Flaky Tests,显然会让人觉得云里雾里。
②所谓Flaky Tests,就是指在被测对象和测试条件都不变的情况下,有时候失败、有时候成功的测试。因此,Flaky Tests实际上就是不稳定的测试,或者随机失败(随机成功)的测试。这意味着相比Flaky Tests,Unreliable Tests或者Random-failure Tests似乎更加容易理解。
③Flaky Tests是在重复测试中出现的。自动化测试的特点之一就是测试更加易于重复执行。因此,相比手动测试,Flaky Tests更多的是自动化测试的产物。在敏捷和DevOps时代,自动化测试是软件测试的主旋律。Flaky Tests也就随着自动化测试的普及而成为普遍的、突出的问题。
二、Flaky Tests的影响?
①有少数人认为Flaky Tests是有益的。因为他们发现,一些隐蔽的、有价值的软件bug,往往是通过Flaky Tests发现的,而那些永远成功的测试反而遗漏了这些问题。这种说法不无道理。然而,主流的看法是:Flaky Tests是有害的。它的有害性体现在多个方面。
②Flaky Tests无法实现测试目标:给定被测软件,我们希望通过测试结果来判断软件是否有bug。理想情况下,如果测试失败,那么软件存在bug;如果测试成功,那么软件没有bug。也就是说,测试结果与软件质量具有确定性的关系。不幸的是,Flaky Tests的存在,破坏了这种确定性的关系,同时造成了一种可恶的随机性。给定被测软件,测试一会儿失败,一会儿成功。这使得我们无法根据测试结果来判断软件质量是好是坏。软件测试的目标也就无法实现。
③Flaky Tests有可能摧毁测试价值:在敏捷和DevOps中,(自动化)测试是有巨大价值的。关注测试结果的绝非只有软件测试人员。软件开发人员基于自动化测试的结果判断软件代码的改动是否可以提交;项目管理人员基于自动化测试的结果判断软件产品是否可以交付。如果自动化测试的结果出现随机性(尤其当Flaky Tests被证明是由非软件代码因素造成时),软件开发人员和项目管理人员对自动化测试的信任度将大打折扣。长此以往,他们可能逐渐忽略甚至以某些方式彻底绕开自动化测试。自动化测试名存实亡之日,就是软件bug长驱直入之时。
④Flaky Tests降低研发团队的效率:在TDD(测试驱动开发)中,代码仓库的任何改动(包括产品代码和测试代码),通常都需要经过(自动化)回归测试集的验证,才能被接受。回归测试集的触发和执行是高频率的。以一个100人的开发/测试团队为例,假如每人每天提交5次代码,那么回归测试集每天将执行500次。如果回归测试集有100个用例,那么每天执行的用例次数将达50000次。即使Flaky Tests的占比低至1% (谷歌目前的比例是2%),Flaky Tests失败的概率是10%,那么每天回归测试集也会因此失败50次。这50次测试失败并不能发现任何新问题,并且我们还需要花费时间检查和确认这50次失败是否由已知的Flaky Tests问题造成。这意味着,由于Flaky Tests的存在,研发团队每天都会浪费一定的资源。
⑤Flaky Tests影响研发团队的协作:在TDD中,开发人员和测试人员紧密协作,是产生高质量软件产品的重要条件。然而,Flaky Tests的存在,有可能给双方的合作带来负面影响,如何理解?这是因为,当Flaky Tests出现时,开发人员会认为“测试用例在软件代码没有任何改动的情况下失败了,测试用例不稳定”;而测试人员则会认为“用同样的测试方法,软件一会儿工作,一会儿不工作,软件功能不稳定”。各自有各自的道理。如果相互抱怨,难免会影响彼此的信任。
三、产生Flaky Tests的原因?
产生Flaky Tests的原因有许多可能。我们只讨论几种常见的原因。
①异步等待:在程序中,我们经常需要执行异步调用,并等待对方的回复。从发起调用请求到接收回复之间存在一个时间间隔。一般来说,为了避免浪费,我们希望等待的时间尽可能短。然而,异步调用存在不确定性。有些时候调用所花费的时间会比平时长。如果等待时间固定为平常的时间,那么调用就会失败。通过回调或者轮询机制,能够在保证效率的同时,避免极端情况下的调用失败。需要注意的是,无论是软件代码还是测试代码,都可能有异步行为,都可能是因此产生Flaky Tests。
②并发:在多线程程序中,线程之间的执行顺序受操作系统调度,通常表现出不确定性。多个线程同时访问共享资源(race condition),多线程死锁(deadlock)等,都可能导致软件行为出现波动,从而产生Flaky Tests。
③资源泄露:如果程序在结束使用后没有及时释放资源,那么,或许前期程序运行正常,但是随着时间的推进,资源最终会被消耗殆尽,程序行为将出现异常。此时,也有可能产生Flaky Tests。
④远程服务:在许多时候,被测软件和测试用例会依赖来自第三方的远程服务,例如远程的文件服务器、时钟同步服务器、证书管理服务器等。一般来说,这些服务不在本地,而是以网络调用的形式提供。经验告诉我们,网络服务并不总是可靠的。远程服务器不稳定、网络通信不稳定、本地网络连接处理不稳定,都可能造成网络服务不可靠。这种情况下是很容易出现Flaky Tests的。应对远程服务不可靠的常用做法是将其Mock掉。
⑤测试依赖性:测试用例通常是批量执行的。多个测试用例共享测试环境、测试配置等全局资源。某个测试用例的执行可能影响后续测试用例。我们期望的是:任意测试用例的执行既不影响其他测试用例,也不受其他测试用例影响。在实际中,这是很难做到的。由测试用例依赖性所导致的Flaky Tests也并不鲜见。
四、如何应对Flaky Tests?
①对自动化测试用例进行可靠性测试:在上面的讨论中,我们可以看到造成Flaky Tests的原因既可能是软件因素,也可能是测试因素。为了减少自动化测试自身的因素,我们可以在自动化测试用例上线(进入回归测试集)之前,对自动化测试用例进行严格的可靠性测试。例如,我们可以不间断地对测试用例重复执行几十次、上百次,只有全部通过之后,我们才认为测试用例的质量过关。这种方法的好处是可以相当程度保证自动化用例的质量,但是牺牲了效率和实时性。
②对Flaky Tests进行重跑处理:当回归测试用例失败时,有两种可能。一是代码的改动破坏了回归测试集,产生了新的问题;二是测试用例是Flaky Tests,其失败和代码的改动没有关系。那么,如何判断是哪一种情况呢?这时,可以自动触发重新执行失败的用例。只有连续失败或者达到一定失败率的情况下,我们才认定用例不是Flaky Tests。但是,重跑也有明显的弊端。一是牺牲了效率,因为重跑必然意味着更长的验证时间;二是可能引入新的Flaky Tests,因为测试用例可能由于这次代码提交而变成Flaky Tests。
③对Flaky Tests进行隔离处理:由于FlakyTests的危害性,有一种普遍做法是将所有的Flaky Tests移到一个专门的隔离区。这种情况下,任何人提交代码将不再执行隔离区中的用例,或者隔离区中用例的执行结果不作为判定代码改动正确性的依据。为了避免隔离区中的Flaky Tests数量膨胀,可以限制隔离区的容量或者用例在隔离区的最大存留时间,倒逼相关人员及时解决Flaky Tests。
④对Flaky Tests进行详细记录、深入分析并举一反三:对FlakyTests进行重跑或者隔离,并不能消除Flaky Tests。实际上,处理Flaky Tests没有捷径可走。再硬的骨头,也只能去啃。对Flaky Tests逐一地记录、分析、解决,是唯一的途径。认识Flaky Tests是解决Flaky Tests的基础。可以通过自动化工具实时地监测Flaky Tests的执行情况,并收集充足的信息供研发人员分析和解决。另外,举一反三也是很重要的。每天都有大量的新代码(软件代码+测试代码)注入到代码仓库中,如果没有举一反三,那么Flaky Tests解决的速度可能还赶不上Flaky Tests增加的速度。
五、总结
①承认Flaky Tests的客观存在是必要的。我们已经说过,Flaky Tests是自动化测试的产物。事实上,测试的自动化程度越高,Flaky Tests的问题也就越突出。例如,自动化回归测试集是在每次代码提交时就执行,还是在软件出包之后才执行,其频率不在一个层级,出现Flaky Tests的概率也不在一个层级。有一种说法:“如果你还没有遇到Flaky Tests,那是因为你的自动化测试还没有做得足够好”。
②另外,需要更多地从代码角度重视Flaky Tests。尽管造成Flaky Tests的原因既可能是产品代码bug,也可能是测试代码bug。我们却不能因为这一点就放弃从产品代码角度排查Flaky Tests。毕竟,对于产品质量来说,漏掉一个真实产品bug的后果,远远比误查一个测试代码bug的后果严重得多。有一种说法:“一个bug最好的藏身之地就是在Flaky Tests中”。因为开发人员会潜意识地认为这是测试问题而不去做任何事情。这是很危险的。
③对于Flaky Tests,“投降论”和“速胜论”都不可取。对Flaky Tests互相推脱或者置之不理,会让软件的质量充满风险;轻视Flaky Tests或者没有投入资源解决Flaky Tests的意识,会让我们吃苦头。与Flaky Tests的斗争是一场持久战。只有经过长期、艰苦的努力,我们才能逐步减少、直至最终消灭Flaky Tests。
六、基于pytest测试框架的Flaky Tests
插件下载(pytest的版本需要高于pytest 6.2)
pip install pytest-ignore-flaky
pytest忽略Flaky Tests
Flaky Tests通常通过,但有时失败。 你应该总是避免片状测试,但不总是可能的。
@pytest.mark.flaky 插件可用于选择性地忽略Flaky Test的失败。
首先用 @pytest.mark.flaky 标记测试测试用例:
import pytest@pytest.mark.flakydef test_mf(): assert 0 == random.randint(0, 10)
①默认情况下, @pytest.mark.flaky 装饰器标记的测试用例默认会执行;当用例执行结果成功时正常执行正常显示用例结果;当用例执行结果失败时,测试用例默认失败重跑一次。
运行结果:
②pytest命令行参数 --ignore-flaky 运行 @pytest.mark.flaky 标记的测试用例。当用例执行成功时执行结果显示正常;当用例执行失败时执行结果显示XFAIL(skip flaky test failure)
运行结果:
去期待陌生,去拥抱惊喜。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~