pytest之mark
背景
本文总结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
先说明该标记的几个参数,经过验证,得出如下结论:
- condition和resason参数必须同时指定,不然会报错。如果condition参数为真,则该标记生效,如果用例实际运行失败,则是xfail, 如果用例实际运行成功,则是xpass。如果condition参数为假,则相当于该标记不生效,执行效果相当于没有这个标记。
- run参数如果指定为False,效果是无论实际用例执行结果是失败还是成功,用例运行结果都记录xfail。如同直接强制指定用例结果为xfail,不管用例的运行,或者说用例根本没有得到执行的机会。
- raises预期用例会产生的指定异常,如果用例实际产生了该异常,则用例结果为xfail。如果用例实际没有产生该异常,在此基础上用例执行失败了,则pytest记录用例结果为fail,若在此基础上用例执行成功,则pytest记录用例结果为xpass
- 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相关推荐
- pytest的mark功能
使用 mark 功能,给测试用例打开标签 在运行测试用例的时候,可根据标签名来过滤要运行的用例 打标签方法: 在测试用例/测试类前面加上:@pytest.mark.标记名 示例: @pytest.ma ...
- 自动化测试框架Pytest使用mark和参数化固定装置、测试函数
目录 一.常见的内置markers 二.查看所有markers 三.注册自定义marks 四.对未注册mark的限制 五. 参数化固定装置.测试函数 一.常见的内置markers usefixture ...
- pytest 之 mark 用法汇总
最近学习到的pytest mark相关用法在此记录一下: mark作为一个pytest中的装饰器,功能丰富, @pytest.mark.skip() #跳过此函数 def test_func01(): ...
- Web自动化之Pytest测试框架
pytest是一个python的单元测试框架,可以用于自动化测试中. 用例规则 pytest命令执行测试时,如果我们不指定具体的文件,PyTest默认从当前路径及其所有子目录中搜索py源文件,所有名字 ...
- UI自动化测试-pytest框架
在进行UI自动化测试的时候,我们需要工具来对测试用例进行收集,执行,标记,参数化.pytest就是这样一个工具. pytest实际是python的一个单元测试框架,其他还有如unittest等,它可以 ...
- pytest自动化测试框架,真正做到从0到1由浅入深详细讲解【万字级】
目录 嗨咯铁汁们,很久不见,我还是你们的老朋友凡叔,这里也感谢各位小伙伴的点赞和关注,你们的三连是我最大的动力哈,我也不会辜负各位的期盼,这里呢给大家出了一个pytest自动化测试框架由浅入深详细讲解 ...
- 接口自动化测试实战之pytest框架+allure讲解
一.前言 本文章主要会讲解Python中pytest框架的讲解,介绍什么是pytest.为何要测试.为何使用以及参考和扩展等等,话不多说,咱们直接进入主题哟. 二.pytest讲解 2.1 什么是py ...
- python全栈工程师 pdf_python全栈工程师项目开发实例实战入门教程百度云
python全栈工程师项目开发实例实战入门教程百度云 课程目录: 开学典礼 pycharm的基本使用 Python基本语法 数值类型数据及运算 字符串的基本操作 字符串的常用方法 列表的基本使用 列表 ...
- Pytest-Pytest框架的使用
Pytest框架的使用 1.Pytest介绍 基于unittest之上的单元测试框架(1).自动发现测试模块和测试方法:(2).断言使用assert+表达式即可;(3).可以设置会话(从运行所有用例开 ...
最新文章
- eclipse 的快捷键
- php计划任务每天12点执行一次,php定时执行计划任务之直接在php中执行
- Java 10 常用集合继承关系图
- jQuery 的属性操作方法
- docker部署mysql项目_Docker部署项目步骤
- 《例说8051:单片机程序设计案例教程》——2-5 寻址方式
- dsoframer java_dsoframer控件动态加载
- 活著就为改变世界---史蒂夫.乔布斯…
- python网络爬虫网易云音乐guihub_GitHub - GreatV/CloudMusic-Crawler: 网易云音乐爬虫,数据可视化。...
- vue+element表格 苹果自带浏览器兼容问题
- 浏览器内核以及渲染过程
- CSS颜色搭配(超级赞的几个网站)
- nginx 配置https 443端口配置
- 后台管理制作首页组件及ui框架的使用
- 如何用Word制作流程图(一)
- 网络流24题(部分)
- 那些你觉得堪称神兵利器的 Chrome 插件
- spring security oauth2 基于 RBAC 的自定义认证
- 华为HCNP网络工程师【从入门到精通】自学视频[肖哥] ¥499-肖宗鹏-专题视频课程...
- 华为推送自定义动作配置