百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

pytest框架进阶自学系列 | 运行的失败管理

haoteby 2025-05-09 18:44 12 浏览

书籍来源:房荔枝 梁丽丽《pytest框架与自动化测试应用》

一边学习一边整理老师的课程内容及实验笔记,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:pytest框架进阶自学系列 | 汇总_热爱编程的通信人的博客-CSDN博客


最多允许失败的测试用例数

当达到最大上限时,退出执行。如未配置,则没有上限。

命令pytest -x遇到第一个失败时,退出执行。

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> pytest -x
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 32 items                                                                                                                                                                                                                     

test_assert_1.py F

============================================================================================================== FAILURES =============================================================================================================== 
______________________________________________________________________________________________________ test_long_str_comparison _______________________________________________________________________________________________________ 

    def test_long_str_comparison():
        str3 = 'abcdef'
        str4 = 'adcdef'
>       assert str3 == str4
E       AssertionError: assert 'abcdef' == 'adcdef'
E         - adcdef
E         ?  ^
E         + abcdef
E         ?  ^

test_assert_1.py:4: AssertionError
========================================================================================================== warnings summary =========================================================================================================== 
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289
  c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289: PytestDeprecationWarning: TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.     
  See https://docs.pytest.org/en/latest/deprecations.html#terminalreporter-writer for more information.
    "TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.\n"

-- Docs: https://docs.pytest.org/en/latest/warnings.html
======================================================================================================= short test summary info ======================================================================================================= 
FAILED test_assert_1.py::test_long_str_comparison - AssertionError: assert 'abcdef' == 'adcdef'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
==================================================================================================== 1 failed, 1 warning in 10.42s ==================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> 

命令pytest --maxfail=2遇到第2个失败时,退出执行。同理,命令pytest --maxfail=3遇到第3个失败时退出执行。

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> pytest -x
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 32 items                                                                                                                                                                                                                     

test_assert_1.py F

============================================================================================================== FAILURES =============================================================================================================== 
______________________________________________________________________________________________________ test_long_str_comparison _______________________________________________________________________________________________________ 

    def test_long_str_comparison():
        str3 = 'abcdef'
        str4 = 'adcdef'
>       assert str3 == str4
E       AssertionError: assert 'abcdef' == 'adcdef'
E         - adcdef
E         ?  ^
E         + abcdef
E         ?  ^

test_assert_1.py:4: AssertionError
========================================================================================================== warnings summary =========================================================================================================== 
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289
  c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289: PytestDeprecationWarning: TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.     
  See https://docs.pytest.org/en/latest/deprecations.html#terminalreporter-writer for more information.
    "TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.\n"

-- Docs: https://docs.pytest.org/en/latest/warnings.html
======================================================================================================= short test summary info ======================================================================================================= 
FAILED test_assert_1.py::test_long_str_comparison - AssertionError: assert 'abcdef' == 'adcdef'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
==================================================================================================== 1 failed, 1 warning in 10.42s ==================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> 

失败运行管理的原理

用例运行失败后,通常希望再次执行失败的用例,看是环境问题还是脚本问题,因此测试方法运行失败需被记录。

这部分内容与第12章缓存目录设置配置内容相一致。cacheprovider插件将执行状态写入缓存文件夹,pytest会将本轮测试的执行状态写入.pytest_cache文件夹,这个行为是由自带的cacheprovider插件实现的。

pytest默认将测试执行的状态写入根目录中的.pytest_cache文件夹,也可以通过在pytest.ini中配置cache_dir选项来自定义缓存的目录,它可以是相对路径,也可以是绝对路径,相对路径指的是相对于pytest.ini文件所在的目录。

例如,我们想把第12章执行的状态的缓存和源码放在一起,该如何实现呢?实现步骤如下。

在src/chapter12/pytest.ini中添加如下配置:

[pytest]
cache_dir = .pytest-cache

这样,即使在项目的根目录下执行src/chapter12/中的用例,也只会在
pytest_book/src/chapter12/.pytest_cache中生成缓存,而不是pytest_book/.pytest_cache中。

(1)在chapter12中复制chapter-2中的test_assert_2.py并改名为test_assert_12.py,需要将内容进行适当修改。

(2)在src路径下执行pytest src/chapter12。

(3)执行状态未写在根目录下,而是写在测试文件所在的目录中(.pytest_cache)。

执行结果如图所示。

cacheprovider插件实现失败管理的准备:

(1)在chapter12下创建pytest.ini文件,代码如下:

[pytest]
cache_dir = .pytest-cache

(2)在chapter12下创建test_failed.py文件,代码如下:

import pytest

@pytest.mark.parametrize('num', [1,2])
def test_failed(num):
    assert num == 1

(3)在chapter12下创建test_pass.py文件,代码如下:

def test_pass():
    assert 1

(4)如果大家是从前到后进行实践,则需要删除test_assert_12.py和.pytest_cache。

(5)再在根目录下执行pytest src/chapter12。

(6)chapter12下会自动创建缓存文件夹及文件.pytest_cache。

执行结果如下,可以看到一共收集到3个测试用例,其中有一个失败,另外两个成功,并且两个执行成功的用例分属不同的测试模块。

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 3 items                                                                                                                                                                                                                      

chapter-12\test_failed.py .F                                                                                                                                                                                                     [ 66%]
chapter-12\test_pass.py .                                                                                                                                                                                                        [100%] 

============================================================================================================== FAILURES =============================================================================================================== 
___________________________________________________________________________________________________________ test_failed[2] ____________________________________________________________________________________________________________ 

num = 2

    @pytest.mark.parametrize('num', [1,2])
    def test_failed(num):
>       assert num == 1
E       assert 2 == 1

chapter-12\test_failed.py:5: AssertionError
======================================================================================================= short test summary info =======================================================================================================
FAILED chapter-12\test_failed.py::test_failed[2] - assert 2 == 1
===================================================================================================== 1 failed, 2 passed in 0.30s ===================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

同时,pytest也在src/chapter12/目录下生成缓存文件夹(.pytest_cache)。

具体介绍一下cacheprovider插件的功能。

--lf,--last-failed:只执行上一轮失败的用例。

缓存中的lastfailed文件记录了上次失败的用例ID,可以通过--cache-show命令查看它的内容。

--cache-show命令是cacheprovider提供的新功能,它不会导致任何用例的执行。

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\ -q --cache-show 'lastfailed'
cachedir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12\.pytest-cache
---------------------------------------------------------------------------------------------------- cache values for 'lastfailed' ---------------------------------------------------------------------------------------------------- 
cache\lastfailed contains:
  {'test_failed.py::test_failed[2]': True}

no tests ran in 0.00s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

可以看到,它记录了一个用例,此用例为上次失败的测试用例的ID:test_failed.py::test_failed[2]。

下次执行,当使用--lf选项时,pytest在收集阶段只会选择这个失败的用例,而忽略其他的用例。命令pytest --lf --collect-only src/chapter12/中的collect-only选项只收集用例而不执行。

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --lf --collect-only .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 1 item                                                                                                                                                                                                                        
<Module test_failed.py>
  <Function test_failed[2]>
run-last-failure: rerun previous 1 failure (skipped 1 file)

======================================================================================================== no tests ran in 0.02s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

仔细观察一下上面的回显,collecting...<Module test_failed.py>只收集到test_fail.py文件中<Function test_failed[2]>,表示第二个执行用例失败了,需要重新执行(跳过5个文件)。1deselected(没有选择),此处的“没有选择”是<Module test_failed.py>中执行通过的第一个用例。跳过5个文件包括pytest.ini和test_pass.py在内的5个文件。

实际上,--lf复写了用例收集阶段的两个钩子方法:pytest_ignore_collect(path,config)和
pytest_collection_modifyitems(session,config,items)。

--ff,--failed-first:先执行上一轮失败的用例,再执行其他的用例。

先通过实践看一看这个命令的效果,再去分析它的实现,命令如下:

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --collect-only -s --ff .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 3 items                                                                                                                                                                                                                       
<Module test_failed.py>
  <Function test_failed[2]>
  <Function test_failed[1]>
<Module test_pass.py>
  <Function test_pass>
run-last-failure: rerun previous 1 failure first

======================================================================================================== no tests ran in 0.02s ======================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

可以看到一共收集到3个测试用例,和正常所收集到的测试用例的顺序相比,上一轮失败的test_failed.py::test_failed[2]用例在最前面,将优先执行。

实际上,-ff只复写了钩子方法:
pytest_collection_modifyitems(session,config,items),它可以过滤或者重新排序所收集到的用例。

--nf,--new-first:先执行新加的或修改的用例,再执行其他的用例。

缓存中的nodeids文件记录了上一轮执行的所有用例,命令如下:

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\ --cache-show 'nodeids'
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
cachedir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12\.pytest-cache
----------------------------------------------------------------------------------------------------- cache values for 'nodeids' ------------------------------------------------------------------------------------------------------ 
cache\nodeids contains:
  ['test_failed.py::test_failed[1]',
   'test_failed.py::test_failed[2]',
   'test_pass.py::test_pass']

======================================================================================================== no tests ran in 0.01s ======================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

从执行结果可以看到上一轮共执行了3个测试用例。

现在可以在test_pass.py中新加一个用例,并修改一下test_failed.py文件中的用例(但是不添加新用例)。

代码如下:

def test_pass():
    assert 1
    
def test_new_pass():
    assert 1

再来执行一下收集命令,命令如下:

执行结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --collect-only -s --nf .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 4 items                                                                                                                                                                                                                      
<Module test_pass.py>
  <Function test_new_pass>
  <Function test_pass>
<Module test_failed.py>
  <Function test_failed[1]>
  <Function test_failed[2]>

======================================================================================================== no tests ran in 0.48s ======================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

可以看到,新加的用例排在最前面,其次修改过的测试用例紧接其后,最后才是旧的用例,这个行为在源码中有所体现。

--cache-clear:先清除所有缓存,再执行用例。

如果上一轮没有失败的用例,则需要先清除缓存,再执行test_pass.py模块(它的用例都是能测试成功的)。

执行及结果如下:

======================================================================================================== no tests ran in 0.48s ======================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --cache-clear -q -s .\chapter-12\test_pass.py
..
2 passed in 0.01s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> 

其结果是不是少了点什么呢?对!因为没有失败的用例,所以不会生成lastfailed文件,那么这个时候再使用--lf和--ff会发生什么呢?我们来试试。

注意:如果我们观察得足够仔细,就会发现现在的缓存目录和之前相比不仅少了lastfailed文件,还少了CACHEDIR.TAG、.gitignore和README.md这3个文件。这是一个Bug,现在pytest的版本是5.2.1,预计会在之后的版本得到修复。

相关推荐

网站seo该怎么优化

一、网站定位在建设一个网站之前,我们首先要做的就是一个网站清晰的定位,会带来转化率相对较高的客户群体,我们建站的目的就是为了营销,只有集中来做某一件事,才会更好的展现我们的网站。在做SEO优化的同时...

3个小技巧教你如何做好SEO优化

  想半路出家做SEO?可是,怎么才做的好呢?关于SEO专业技术弄懂搜索引擎原理,咱们做搜索引擎排名的首先就是要了解搜索引擎的工作原理,对SEO优化有更深入了解之后再来做SEO,你就能从搜索引擎的视点...

SEO指令分享:filetype指令

filetype用于搜索特定的文件格式。百度和谷歌都支持filetype指令。比如搜索filetype:pdf今日头条返回的就是包含今日头条这个关键词的所有pdf文件,如下图:百度只支持:pdf...

网站seo优化技巧大全

SEO在搜索引擎中对检索结果进行排序,看谁最初是在用户的第一眼中看到的。实际上,这些排名都是通过引擎的内部算法来实现的。例如,百度算法很有名。那么,对百度SEO的优化有哪些小技巧?下面小编就会说下针对...

小技巧#10 某些高级的搜索技巧

由于某些原因,我的实验场所仅限百度。1.关键词+空格严格说来这个不能算高级,但关键词之间打空格的办法确实好用。我习惯用右手大拇指外侧敲击空格键,这个习惯在打英文报告时尤其频繁。2.site:(请不要忽...

MYSQL数据库权限与安全

权限与安全数据库的权限和数据库的安全是息息相关的,不当的权限设置可能会导致各种各样的安全隐患,操作系统的某些设置也会对MySQL的安全造成影响。1、权限系统的工作原理...

WPF样式

UniformGrid容器<UniformGridColumns="3"Rows="3"><Button/>...

mysql自动备份,并zabbix检测备份文件是否正常,备份文件大小

推荐...

MySQL学到什么程度?才有可以在简历上写精通

前言如今互联网行业用的最多就是MySQL,然而对于高级Web面试者,尤其对于寻找30k下工作的求职者,很多MySQL相关知识点基本都会涉及,如果面试中,你的相关知识答的模糊和不切要点,基...

jquery的事件名称和命名空间的方法

我们先看一些代码:当然,我们也可以用bind进行事件绑定。我们看到上面的代码,我们可以在事件后面,以点号,加我们的名字,就是事件命名空间。所谓事件命名空间,就是事件类型后面以点语法附加一个别名,以便引...

c#,委托与事件,发布订阅模型,观察者模式

什么是事件?事件(Event)基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。通过委托使用事件事件在类中声明且生成,且通过...

前端分享-原生Popover已经支持

传统网页弹窗开发需要自己处理z-index层级冲突、编写点击外部关闭的逻辑、管理多个弹窗的堆叠顺序。核心优势对比:...

Axure 8.0 综合帖——新增细节内容

一、钢笔工具与PS或者AI中的钢笔工具一样的用法。同样有手柄和锚点,如果终点和起点没有接合在一起,只要双击鼠标左键即可完成绘画。画出来的是矢量图,可以理解为新的元件。不建议通过这个工具来画ICON图等...

PostgreSQL技术内幕28:触发器实现原理

0.简介在PostgreSQL(简称PG)数据库中,触发器(Trigger)能够在特定的数据库数据变化事件(如插入、更新、删除等)或数据库事件(DDL)发生时自动执行预定义的操作。触发器的实现原理涉及...

UWP开发入门(十七)--判断设备类型及响应VirtualKey

蜀黍我做的工作跟IM软件有关,UWP同时会跑在电脑和手机上。电脑和手机的使用习惯不尽一致,通常我倾向于根据窗口尺寸来进行布局的变化,但是特定的操作习惯是依赖于设备类型,而不是屏幕尺寸的,比如聊天窗口的...