背景

本文总结pytest提供的mark功能。

说明

mark可分为2类:

  • 一类是系统内置的mark,不同的mark标记提供不同的功能。
  • 二类是自定义的mark。该类mark主要用于给测试用例分门别类,使得运行测试时可以指定运行符合哪一类标记的测试用例。

系统内置mark

系统内置mark可通过pytest --markers指令查看。
如下:有一些笔者没弄懂,请了解的读者解惑。

'''
@pytest.mark.flaky(reruns=1, reruns_delay=0):将test标记为重新运行“reruns”的值代表的次数。在重新运行之间添加'reruns_delay'秒的延迟。@pytest.mark.allure_label: allure label marker(没搞懂)@pytest.mark.allure_link: allure link marker(没搞懂)@pytest.mark.allure_display_name: allure test name marker(没搞懂)@pytest.mark.allure_description: allure description(没搞懂)@pytest.mark.allure_description_html: allure description html(没搞懂)@pytest.mark.filterwarnings(warning): 向给定的测试添加一个警告过滤器。参考https://docs.pytest.org/en/latest/warnings.html pytest-mark-filterwarnings(没有模拟出来,warning应该被限制只能传入某个警告的对象名)@pytest.mark.skip(reason=None):使用可选的原因跳过给定的测试函数。例如:skip(reason="no way of current testing this")跳过测试。@pytest.mark.skipif(condition,reason):如果eval(条件)结果为真值,则跳过给定的测试函数。评估发生在模块全局上下文中。例如:skipif(“系统。如果我们在win32平台上,平台== "win32"')将跳过测试。参见https://docs.pytest.org/en/latest/skipping.html@pytest.mark.xfail(condition, reason=None, run=True, raises =None, strict=False):如果eval(condition)的值为真,则将测试函数标记为预期失败。可选地指定更好报告的理由,如果您甚至不想执行测试函数,则run=False。如果只期望特定的异常,您可以在引发中列出它们,如果测试以其他方式失败,则将报告为真正的失败。参见https://docs.pytest.org/en/latest/skipping.html@pytest.mark.parametrize(argnames, argvalues):调用一个测试函数多次,依次传递不同的参数。如果argnames只指定一个名称,则argvalues通常需要一个值列表;如果argnames指定多个名称,则需要一个值元组列表。例如:@ parametertrize ('arg1',[1,2])将导致对修饰测试函数的两个调用,一个调用arg1=1,另一个调用arg1=2。有关更多信息和示例,请参见https://docs.pytest.org/en/latest/parametertrize.html。@pytest.mark.usefixtures(fixturename1, fixturename2, ...):将测试标记为会使用所有指定的fixture。参考https://docs.pytest.org/en/latest/fixture.html usefixtures@pytest.mark.tryfirst:标记一个钩子实现函数,这样插件机制就会尽可能早地调用它。(没搞懂)@pytest.mark.trylast:标记一个钩子实现函数,使插件机制尽可能晚地调用它。(没搞懂)'''

依次通过示例总结以上常用的内置mark:

@pytest.mark.flaky(reruns=1, reruns_delay=0)

使用flaky标记,指示如下用例失败会重新运行2次,重新运行的事件间隔为0s。

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.flaky(reruns = 2)
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 9# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
stdout:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%]
test_case/test_func.py::test_add_by_func_aaa RERUN                       [100%]
test_case/test_func.py::test_add_by_func_aaa RERUN                       [100%]
test_case/test_func.py::test_add_by_func_aaa FAILED                      [100%]================================== FAILURES ===================================
____________________________ test_add_by_func_aaa _____________________________@pytest.mark.flaky(reruns = 2)def test_add_by_func_aaa():a = 4b = 6
>    assert add(a,b) == 9
E    assert 10 == 9
E      -10
E      +9test_case\test_func.py:14: AssertionError
==================== 1 failed, 1 passed, 2 rerun in 0.12s =====================
[Finished in 1.5s]
'''

@pytest.mark.skip(reason=None):

使用可选的原因跳过给定的测试函数。例如:skip(reason=“no way of current testing this”)跳过测试。

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:@pytest.mark.skip()def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.skip(reason="No No No")
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 9# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class SKIPPED              [ 50%]
test_case/test_func.py::test_add_by_func_aaa SKIPPED                     [100%]============================= 2 skipped in 0.04s ==============================
[Finished in 1.4s]
'''

不知道把原因说明显示到哪里去了。

@pytest.mark.skipif(condition,reason):

如果eval(条件)结果为真值,则跳过给定的测试函数。评估发生在模块全局上下文中。例如:skipif(“系统。如果我们在win32平台上,平台== “win32”’)将跳过测试。参见https://docs.pytest.org/en/latest/skipping.html

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:@pytest.mark.skipif(1==2,reason="No No No")def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.skipif(1==1,reason="Y Y Y")
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 10# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%]
test_case/test_func.py::test_add_by_func_aaa SKIPPED                     [100%]======================== 1 passed, 1 skipped in 0.04s =========================
[Finished in 1.4s]
'''

这个标记还必须指定reason,不然会报错。但是也没搞懂reason显示到哪里去了。

@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False):

如果eval(condition)的值为真,则将测试函数标记为预期失败。可选地指定更好报告的理由,如果您甚至不想执行测试函数,则run=False。如果只期望特定的异常,您可以在引发中列出它们,如果测试以其他方式失败,则将报告为真正的失败。参见https://docs.pytest.org/en/latest/skipping.html

先说明该标记的几个参数,经过验证,得出如下结论:

  1. condition和resason参数必须同时指定,不然会报错。如果condition参数为真,则该标记生效,如果用例实际运行失败,则是xfail, 如果用例实际运行成功,则是xpass。如果condition参数为假,则相当于该标记不生效,执行效果相当于没有这个标记。
  2. run参数如果指定为False,效果是无论实际用例执行结果是失败还是成功,用例运行结果都记录xfail。如同直接强制指定用例结果为xfail,不管用例的运行,或者说用例根本没有得到执行的机会。
  3. raises预期用例会产生的指定异常,如果用例实际产生了该异常,则用例结果为xfail。如果用例实际没有产生该异常,在此基础上用例执行失败了,则pytest记录用例结果为fail,若在此基础上用例执行成功,则pytest记录用例结果为xpass
  4. strict参数是生效的参数,如果指定strict=True,则当对于标记为xfail的用例,但执行结果为xpass的用例,该用例的执行结果,会强制被指定为fail.
    xfail:预期失败,实际也失败
    xpass:预期失败,但实际成功了

xfail示例:

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.xfail()
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 9# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%]
test_case/test_func.py::test_add_by_func_aaa XFAIL                       [100%]======================== 1 passed, 1 xfailed in 0.10s =========================
[Finished in 1.5s]
'''

xpass示例:

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.xfail()
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 10# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%]
test_case/test_func.py::test_add_by_func_aaa XPASS                       [100%]======================== 1 passed, 1 xpassed in 0.05s =========================
[Finished in 1.4s]
'''

strict=True示例:

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:def test_add_by_class(self):assert add(2,3) == 5@pytest.mark.xfail(strict=True)
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 10# ./run_test.py
import pytestif __name__ == '__main__':pytest.main(['-v'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 itemstest_case/test_func.py::TestFunc::test_add_by_class PASSED               [ 50%]
test_case/test_func.py::test_add_by_func_aaa FAILED                      [100%]================================== FAILURES ===================================
____________________________ test_add_by_func_aaa _____________________________
[XPASS(strict)]
========================= 1 failed, 1 passed in 0.04s =========================
[Finished in 1.4s]
'''

Tips:还可以通过pytest.ini配置文件达到strict=True的效果。这样的效果范围将是全局的。

pytest.ini

[pytest]
xfail_strict = true

@pytest.mark.parametrize(argnames, argvalues):

调用一个测试函数多次,依次传递不同的参数。如果argnames只指定一个名称,则argvalues通常需要一个值列表;如果argnames指定多个名称,则需要一个值元组列表。例如:@ parametertrize (‘arg1’,[1,2])将导致对修饰测试函数的两个调用,一个调用arg1=1,另一个调用arg1=2。有关更多信息和示例,请参见https://docs.pytest.org/en/latest/parametertrize.html。

测试用例的参数化标记,该标记将单独在另外的文章中总结

@pytest.mark.usefixtures(fixturename1, fixturename2, …):

将测试标记为会使用所有指定的fixture。参考https://docs.pytest.org/en/latest/fixture.html usefixtures

pytest中指定测试用例使用fixture方法的标记。
指定测试用例使用fixture方法还可以通过像给函数传参的方式一般使用:
用法示例如下:

def test_case_001(fixturename1, fixturename2, ...):# 打印ixturename1代表的fixture方法的返回值print(ixturename1)

自定义标记:

指定pytest运行时,需要指定-m选项,来使用自定义标记。
该类mark主要用于给测试用例分门别类,使得运行测试时可以指定运行符合哪一类标记的测试用例。官方说法是将测试用例标记并分组,以便快速选中并运行。
-m选项可以使用表达式指定多个标记名。
比如:
选中同时符合mark1和mark2标记的用例:“-m mark1 and mark2”, 如果一个用例只有mark1标记,没有mark2标记,则是不会被选中。
仅选中符合mark1但不符mark2标记的用例:“-m mark1 and not mark2”,如果一个用例只有mark1标记,没有mark2标记,则会被选中。
mark1或者mark2中有一个符合就选中的用例:“-m mark1 or mark2”。
示例:

# ./test_case/test_func.py
import pytest
from func import *class TestFunc:@pytest.mark.firstdef test_add_by_class(self):assert add(2,3) == 5@pytest.mark.second
def test_add_by_func_aaa():a = 4b = 6assert add(a,b) == 10# ./run_test.py
# ./run_test.py
import pytestif __name__ == '__main__':# 该参数下:预期只会运行first标记的test_add_by_classpytest.main(['-v','-m', 'first and not second'])'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 items / 1 deselected / 1 selectedtest_case/test_func.py::TestFunc::test_add_by_class PASSED               [100%]============================== warnings summary ===============================
D:\Python3.7\lib\site-packages\_pytest\mark\structures.py:327D:\Python3.7\lib\site-packages\_pytest\mark\structures.py:327: PytestUnknownMarkWarning: Unknown pytest.mark.first - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.htmlPytestUnknownMarkWarning,D:\Python3.7\lib\site-packages\_pytest\mark\structures.py:327D:\Python3.7\lib\site-packages\_pytest\mark\structures.py:327: PytestUnknownMarkWarning: Unknown pytest.mark.second - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
================= 1 passed, 1 deselected, 2 warnings in 0.04s =================
[Finished in 1.4s]
'''

这里有些警告,是因为我们的自定义标记没有注册,pytest识别为不合法标记。

如何注册自定义标记
通过在项目根目录下创建pytest.ini文件,然后添加section\option\value

[pytest]
markers=
markname1:description1
markname2:description2
addopts = --strict #该配置可以防止mark的拼写错误

pytest之mark相关推荐

  1. pytest的mark功能

    使用 mark 功能,给测试用例打开标签 在运行测试用例的时候,可根据标签名来过滤要运行的用例 打标签方法: 在测试用例/测试类前面加上:@pytest.mark.标记名 示例: @pytest.ma ...

  2. 自动化测试框架Pytest使用mark和参数化固定装置、测试函数

    目录 一.常见的内置markers 二.查看所有markers 三.注册自定义marks 四.对未注册mark的限制 五. 参数化固定装置.测试函数 一.常见的内置markers usefixture ...

  3. pytest 之 mark 用法汇总

    最近学习到的pytest mark相关用法在此记录一下: mark作为一个pytest中的装饰器,功能丰富, @pytest.mark.skip() #跳过此函数 def test_func01(): ...

  4. Web自动化之Pytest测试框架

    pytest是一个python的单元测试框架,可以用于自动化测试中. 用例规则 pytest命令执行测试时,如果我们不指定具体的文件,PyTest默认从当前路径及其所有子目录中搜索py源文件,所有名字 ...

  5. UI自动化测试-pytest框架

    在进行UI自动化测试的时候,我们需要工具来对测试用例进行收集,执行,标记,参数化.pytest就是这样一个工具. pytest实际是python的一个单元测试框架,其他还有如unittest等,它可以 ...

  6. pytest自动化测试框架,真正做到从0到1由浅入深详细讲解【万字级】

    目录 嗨咯铁汁们,很久不见,我还是你们的老朋友凡叔,这里也感谢各位小伙伴的点赞和关注,你们的三连是我最大的动力哈,我也不会辜负各位的期盼,这里呢给大家出了一个pytest自动化测试框架由浅入深详细讲解 ...

  7. 接口自动化测试实战之pytest框架+allure讲解

    一.前言 本文章主要会讲解Python中pytest框架的讲解,介绍什么是pytest.为何要测试.为何使用以及参考和扩展等等,话不多说,咱们直接进入主题哟. 二.pytest讲解 2.1 什么是py ...

  8. python全栈工程师 pdf_python全栈工程师项目开发实例实战入门教程百度云

    python全栈工程师项目开发实例实战入门教程百度云 课程目录: 开学典礼 pycharm的基本使用 Python基本语法 数值类型数据及运算 字符串的基本操作 字符串的常用方法 列表的基本使用 列表 ...

  9. Pytest-Pytest框架的使用

    Pytest框架的使用 1.Pytest介绍 基于unittest之上的单元测试框架(1).自动发现测试模块和测试方法:(2).断言使用assert+表达式即可;(3).可以设置会话(从运行所有用例开 ...

最新文章

  1. eclipse 的快捷键
  2. php计划任务每天12点执行一次,php定时执行计划任务之直接在php中执行
  3. Java 10 常用集合继承关系图
  4. jQuery 的属性操作方法
  5. docker部署mysql项目_Docker部署项目步骤
  6. 《例说8051:单片机程序设计案例教程》——2-5 寻址方式
  7. dsoframer java_dsoframer控件动态加载
  8. 活著就为改变世界---史蒂夫.乔布斯…
  9. python网络爬虫网易云音乐guihub_GitHub - GreatV/CloudMusic-Crawler: 网易云音乐爬虫,数据可视化。...
  10. vue+element表格 苹果自带浏览器兼容问题
  11. 浏览器内核以及渲染过程
  12. CSS颜色搭配(超级赞的几个网站)
  13. nginx 配置https 443端口配置
  14. 后台管理制作首页组件及ui框架的使用
  15. 如何用Word制作流程图(一)
  16. 网络流24题(部分)
  17. 那些你觉得堪称神兵利器的 Chrome 插件
  18. spring security oauth2 基于 RBAC 的自定义认证
  19. 华为HCNP网络工程师【从入门到精通】自学视频[肖哥] ¥499-肖宗鹏-专题视频课程...
  20. 华为推送自定义动作配置

热门文章

  1. 市值腰斩,快手如何渡过低谷期?
  2. 黑马程序员-----------------交通灯管理系统
  3. C++与字符集、字符编码
  4. FFT—快速傅里叶变换算法——matlab(1)
  5. ASO优化:关于后台关键词设置的逗号的使用
  6. Wind量化接口常见错误码
  7. 红帽Linux安装ffmpeg
  8. selenium之 玩转鼠标键盘操作(ActionChains)
  9. 优达学城Numpy与Pandas笔记
  10. ios开发-inputView和inputAccessoryView