自动化测试中,如何增加失败重试机制!

01、前言

在执行自动化测试用例时,会发现有时候用例失败并非代码问题,而是由于服务正在发版,导致请求失败,从而降低了自动化用例的稳定性,最后还要花时间定位到底是自身case的原因还是业务逻辑问题,还是其他原因,增加了定位成本。增加容错机制,失败重试,会解决大部分由于网络原因、服务重启等原因造成的case失败问题。那该如何增加失败重试机制呢?带着问题我们一起探索。

02、pytest-rerunfailures 插件

先给出答案,我们将使用 pytest-rerunfailures 插件来实现失败重试功能。

什么是 pytest-rerunfailures ?

pytest-rerunfailures 是一个基于 pytest 框架的插件,它允许我们对测试用例进行失败重试。当一个测试用例失败时,插件会自动重新运行失败的测试用例,直到达到预定的重试次数或测试用例通过为止。这样可以增加用例的稳定性,并减少因为偶发性问题导致的测试失败。

如何使用 pytest-rerunfailures ?

  • 方式一

首先,确保已经安装了 pytest-rerunfailures 插件。可以使用以下命令进行安装:

pip install pytest-rerunfailures

安装完成后,在项目中使用 pytest 运行测试用例时,pytest-rerunfailures 插件会自动生效。

接下来,在编写测试用例时,可以通过添加 @pytest.mark.flaky 装饰器将需要重试的测试用例标记起来。例如:

test_demo.py

import pytest@pytest.mark.flaky(reruns=3, reruns_delay=2)def test_case():    assert 1 == 2

在上述示例中,我们使用了 @pytest.mark.flaky 装饰器来标记测试用例 test_case 为可重试的。参数 reruns 指定了重试次数,而 reruns_delay 则指定了每次重试之间的延迟时间(以秒为单位)。

我们来运行case,看一下执行结果:

执行命令:pytest -s -v test_demo.py::test_case,会看到如下结果:

RERUNtest_dir/test_demo.py::test_case RERUNtest_dir/test_demo.py::test_case RERUNtest_dir/test_demo.py::test_case FAILED

可以看到,重试了3次,最终结果为失败。

注意:如果你是在pycharm中点击绿色三角形直接运行是不生效的

总结一下:

当运行测试时,如果测试用例失败,pytest-rerunfailures 插件会根据我们配置的重试次数和延迟时间自动重新运行该测试用例,直到达到最大重试次数或测试通过为止。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

  • 方式二

除了使用装饰器来标记测试用例外,pytest-rerunfailures 还支持使用命令行选项和配置文件的方式进行配置。

命令行执行的话,可以这样写:

pytest -s -v --reruns 3 --reruns-delay 2 test_demo.py::test_case

或者代码运行的话,可以这样写:

pytest.main(["-s", "-v", "--reruns", "3", "--reruns-delay", "2", "test_demo.py::test_case"])

03、运行机制

到这里,应该会使用了。我们简单概括一下它的运行机制:

1、pytest 通过插件系统加载 pytest-rerunfailures 插件,并启用其功能。

2、当 pytest 运行测试时,对每个测试用例的执行进行监控。

3、如果一个测试用例执行失败,pytest-rerunfailures 插件会捕获该失败,并判断是否需要进行重试。

4、如果该测试用例被标记为可重试(使用了 @pytest.mark.flaky 装饰器),插件会根据配置的重试次数和延迟时间重新运行该测试用例。

5、在每次重试之前,插件会根据设置的延迟时间暂停一段时间。

6、如果测试用例在重试次数达到上限之前通过了,即成功执行,则插件会将该测试用例标记为通过。

7、如果测试用例在达到最大重试次数后仍然失败,则插件会返回最后一次失败的结果作为最终的结果

总结起来,pytest-rerunfailures 插件在测试执行失败时,根据配置的重试次数和延迟时间重新运行测试用例,并根据重试结果判断最终的测试结果。这样可以提高测试用例的稳定性,并减少偶发性问题导致的测试失败。

04、源码解读

使用阶段,我们使用 mark 标记,那源码中应该添加了该标记。

def pytest_configure(config):    # add flaky marker    config.addinivalue_line(        "markers",        "flaky(reruns=1, reruns_delay=0): mark test to re-run up "        "to 'reruns' times. Add a delay of 'reruns_delay' seconds "        "between re-runs.",    )    ......

简单解释一下:

  • pytest_configure(config) 是 pytest 的一个钩子函数,用于在 pytest 配置阶段对配置进行自定义操作。

  • config.addinivalue_line() 是 pytest 的配置方法,用于向配置中添加新的配置项或配置信息。

  • 在这段代码中,通过 config.addinivalue_line() 方法,插件向 pytest 的配置中加入了一行字符串。

  • 这行字符串指定了标记名称为 "flaky",并使用参数 reruns 和 reruns_delay 来说明重试次数和延迟时间的默认值。

  • 标记的含义是将被标记的测试用例重新运行最多 "reruns" 次,每次重试之间间隔 "reruns_delay" 秒。

通过这个自定义的标记,就可以使用 @pytest.mark.flaky 装饰器来标记需要进行重试的测试用例,并且可以在装饰器中指定具体的重试次数和延迟时间。

我们看看实现失败重试的源码,这才是重点。

def pytest_runtest_protocol(item, nextitem):    """    Run the test protocol.
    Note: when teardown fails, two reports are generated for the case, one for    the test case and the other for the teardown error.    """    reruns = get_reruns_count(item)    if reruns is None:        # global setting is not specified, and this test is not marked with        # flaky        return
    # while this doesn't need to be run with every item, it will fail on the    # first item if necessary    check_options(item.session.config)    delay = get_reruns_delay(item)    parallel = not is_master(item.config)    db = item.session.config.failures_db    item.execution_count = db.get_test_failures(item.nodeid)    db.set_test_reruns(item.nodeid, reruns)
    if item.execution_count > reruns:        return True
    need_to_run = True    while need_to_run:        item.execution_count += 1        item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)        reports = runtestprotocol(item, nextitem=nextitem, log=False)
        for report in reports:  # 3 reports: setup, call, teardown            report.rerun = item.execution_count - 1            if _should_not_rerun(item, report, reruns):                # last run or no failure detected, log normally                item.ihook.pytest_runtest_logreport(report=report)            else:                # failure detected and reruns not exhausted, since i < reruns                report.outcome = "rerun"                time.sleep(delay)
                if not parallel or works_with_current_xdist():                    # will rerun test, log intermediate result                    item.ihook.pytest_runtest_logreport(report=report)
                # cleanin item's cashed results from any level of setups                _remove_cached_results_from_failed_fixtures(item)                _remove_failed_setup_state_from_session(item)
                break  # trigger rerun        else:            need_to_run = False
        item.ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location)
    return True

简单解释一下:

首先,通过函数 get_reruns_count(item) 获取当前测试用例需要重试的次数。如果没有设置重试次数,则直接返回。

然后,检查配置选项并获取重试的延迟时间,并确定是否运行在并行模式下。还会获取失败记录数据库对象,并获取当前测试用例已经执行的次数。

接下来,通过比较已执行次数和设定的重试次数,判断是否需要进行重试。如果已执行次数大于等于设定的重试次数,则不再进行重试,直接返回。

如果需要重试,会进入一个循环,每次重试会增加已执行次数。在重试过程中,会调用 pytest_runtest_logstart 函数记录测试用例开始执行的日志。

然后,通过调用 runtestprotocol 函数执行测试用例,并获取测试结果。在这里,生成的报告会被标记为执行次数减一,以便区分原始执行和重试执行的报告。

接着,通过 _should_not_rerun 函数判断当前报告是否满足不需要重试的条件。如果满足,则继续执行后续操作。

如果报告表明需要重试,并且重试次数未达到设定的次数,会将报告的结果设置为 "rerun",并根据设定的延迟时间暂停一段时间。

然后,根据并行模式和当前使用的 xdist 版本,决定是否记录中间结果。同时,会清除缓存的结果和执行状态。

之后,重试循环会继续,直到不满足重试条件为止。最后,会调用 pytest_runtest_logfinish 函数记录测试用例结束执行的日志。

最后,函数返回 True,表示已经实现重试机制。

总结起来,这段代码通过循环执行测试用例,并在满足重试条件时进行重试,直到满足退出条件为止。在重试过程中,会记录日志、生成报告,并根据设定的重试次数和延迟时间进行控制。

04、最后

失败重试功能并不是解决所有测试问题的法宝,它应该被视为一种提高测试稳定性的辅助手段。在使用 pytest-rerunfailures 进行失败重试时,我们应该仔细分析失败的原因,确保重试次数和延迟时间设置合理,并与团队成员共同讨论和决定是否需要重试测试用例。

总结起来,pytest-rerunfailures 是一个非常有用的工具,可以提高测试用例的稳定性。通过使用它,我们可以轻松地实现失败重试功能,并减少由于偶发性问题导致的测试失败。

另外源码中,看到了 pytest_runtest_logstart 等,可能有些同学不明白这是干嘛用的,之后我们专门写一篇文章来介绍它的作用。

END今天的分享就到此结束了!点赞关注不迷路!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/591728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理

​随着市场竞争的加剧和企业规模的扩大&#xff0c;招采管理逐渐成为企业核心竞争力的重要组成部分。为了提高招采工作的效率和质量&#xff0c;我们提出了一种基于电子化平台的解决方案。该方案旨在通过电子化招投标&#xff0c;使得招标采购的质量更高、速度更快&#xff0c;…

宣传照(私密)勿转发

精美的海报通常都是由UI进行精心设计的&#xff0c;现在有100 件商品需要进行宣传推广&#xff0c;如果每个商品都出一张图显然是不合理的&#xff0c;且商品信息各异。因此需要通过代码的形式生成海报。对此&#xff0c;我也对我宣传一波&#xff0c;企图实现我一夜暴富的伟大…

贪心算法part04 860柠檬水找零 406根据身高重建队列

860 柠檬水找零 406 根据身高重建队列 452 用最少数量的箭引爆气球

六、HTML 段落

HTML 可以将文档分割为若干段落。 一、HTML 段落 段落是通过 <p> 标签定义的。 <p>这是一个段落 </p> <p>这是另一个段落</p> 注意&#xff1a;浏览器会自动地在段落的前后添加空行。&#xff08;</p> 是块级元素&#xff09; 二、不…

[蓝桥杯知识学习] 树链

DFS序 什么是DFS序 怎么求DFS序 进入操作&#xff0c;将有计数 出&#xff1a;可以理解为&#xff0c;没有孩子可以去了&#xff08;不能&#xff0c;向下行动&#xff1a;对应于程序里的入栈&#xff09;&#xff0c;所以回到父结点&#xff08;向上行动&#xff0c;对应于程…

SCENIC+:增强子和基因调控网络的单细胞多组学推理

SCENIC&#xff1a;增强子和基因调控网络的单细胞多组学推理 摘要IntroductionSCENIC 使用超过 30,000 个 TF 基序来预测 eGRNSCENIC 在 PBMC 多组数据上的图示SCENIC prioritizes functional enhancers &#xff08;SCENIC 优先考虑功能增强剂&#xff09;SCENIC simulates ph…

从0到1实战,快速搭建SpringBoot工程

目录 一、前言 二、准备工作 2.1 安装JDK 2.2 安装Maven 2.3 下载IDEA 三、从0到1搭建 3.1 创建SpringBoot工程 3.2 运行SpringBoot工程 四、总结 一、前言 SpringBoot是一个在Spring框架基础上构建的开源框架&#xff0c;不仅继承了Spring框架原有的优秀特性&#x…

Selenium自动化测试之学会元素定位

这是我经常被问到的一个问题&#xff0c;也是我很讨厌回答的问题&#xff0c;因为要想回答这个问题需要知道上下文。什么样式的元素&#xff0c;有哪些属性&#xff0c;是否有表单嵌套&#xff0c;都尝试了哪些定位方法。。。而且没几个提问者能事先详细的说明这些。哪儿像提bu…

centos7通过systemctl启动springboot服务代替java -jar方式启动

背景&#xff1a;以前启动jar包都是通过java -jar&#xff0c;后面了解到一种注册服务式启动jar包的方式&#xff0c;所以做个记录。 注意&#xff1a;我在写该篇博客的时候&#xff0c;给脚本代码都加了#注释来解释该行脚本命令的意思&#xff0c;所以可能出现复制该篇博客脚本…

Android 13 - Media框架(29)- MediaCodec(四)

上一节我们了解了如何通过 onInputBufferAvailable 和 getInputBuffer 获取到 input buffer index&#xff0c;接下来我们一起学习上层如何拿到buffer并且向下写数据的。 1、获取 input Buffer 获取 MediaCodec 中的 buffer 有两种方式&#xff0c;一种是调用 getInputBuffers…

Jsonpath - 数据中快速查找和提取的强大工具

JSON&#xff08;JavaScript Object Notation&#xff09;在现代应用程序中广泛使用&#xff0c;但是如何在复杂的JSON数据中 查找和提取所需的信息呢&#xff1f; JSONPath是一种功能强大的查询语言&#xff0c;可以通过简单的表达式来快速准确地定位和提取JSON数据。本文将介…

如何将内容转化为流量?媒介盒子分享

软文营销就是将内容转为流量的常见做法&#xff0c;但是有许多企业在做内容时往往一头雾水导致效果不佳&#xff0c;做内容不是光靠写就可以的&#xff0c;还需要做好选题、类型、结构等&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;如何将内容转化为流量。 一、 确定内…

【SpringBoot开发】之商城项目案例(购物车相关操作)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringBoot开发之商城项目系列》。&#x1f3af…

2023最新租号平台系统源码支持单独租用或合租使用

这是一款租号平台源码&#xff0c;采用常见的租号模式。目前网络上还很少见到此类类型的源码。 平台的主要功能如下&#xff1a; 支持单独租用或采用合租模式&#xff1b; 采用易支付通用接口进行支付&#xff1b; 添加邀请返利功能&#xff0c;以便站长更好地推广&#xf…

每天刷两道题——第三天

1.1两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09; 输入&#xff1a;[1,2,3,4] 输出&#xff1a;[2,1,4,3…

祝贺首届兽医专业学位研究生创新创业大赛圆满闭幕

为进一步贯彻落实科教兴国、农业强国发展战略&#xff0c;适应兽医行业、产业发展需求&#xff0c;提高兽医专业学位研究生实践创新能力&#xff0c;推动兽医领域高层次应用型人才培养供给侧改革&#xff0c;促进兽医专业学位教育高质量发展&#xff0c;12月28日由中国学位与研…

什么是分布式锁

想象一下&#xff0c;如果没有分布式锁&#xff0c;多个分布式节点同时涌入一个共享资源的访问时&#xff0c;就像一群饥肠辘辘的狼汇聚在一块肉前&#xff0c;谁都想咬一口&#xff0c;最后弄得肉丢了个精光&#xff0c;大家都吃不上。 而有了分布式锁&#xff0c;就像给这块肉…

Python轴承故障诊断 (九)基于VMD+CNN-BiLSTM的故障分类

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Python轴承故障诊断 (一)短时傅里叶变换STFT Python轴承故障诊断 (二)连续小波变换CWT_pyts 小波变换 故障-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD_轴承诊断 …

JAVAEE初阶相关内容第二十弹--HTTP协议

写在前&#xff1a;2024年啦&#xff01;新的一年要努力学习啦 本篇博客围绕HTTP协议&#xff0c;对HTTP协议进行了解&#xff0c;需要理解其工作过程&#xff0c;对HTTP协议格式要清楚&#xff0c;通过抓包工具进行协议分析&#xff0c;认识“方法”、“请求报头”&#xff0c…

爬虫与反爬-localStorage指纹(某易某盾滑块指纹检测)(Hook案例)

概述&#xff1a;本文将用于了解爬虫中localStorage的检测原理以及讲述一个用于检测localStorage的反爬虫案例&#xff0c;最后对该参数进行Hook断点定位 目录&#xff1a; 一、LocalStorage 二、爬虫中localStorage的案例&#xff08;以某盾滑块为例&#xff09; 三、如何…