pytest提供了标记的机制,允许我们使用markers来标记测试函数,通过不同的标记实现不同的运行策略,熟练使用mark标记表达式对于以后分类用例非常有用处,方便我们能够准确的运行想要运行的测试用例,可以节省很多时间
一个函数可以标记多个markers,一个markers也可以用来标记多个函数
输入 pytest --markers 可以查看所有的mark标签,有内置的makers可以使用,也可以自己定义
@pytest.mark.{marker_name}:自定义标签或分类测试用例
描述:@pytest.mark.{marker_name}自定义一个mark,然后pytest -v -m {marker_name}只运行标记了{marker_name}的函数,pytest -v -m "not {marker_name}"来运行未标记{marker_name}的。
1.自定义mark,需要先注册标记,运行时才不会出现warnings(可以通过在pytest.ini文件中注册或使用自定义pytest_configure挂钩来禁用自定义标记的警告)
将自定义的marker_name写入pytest.ini,例如:
[pytest]
markers=
P0: level P0
P1: level p1
P2: level p2
dong: testcase created by dong
mandy: testcase created by mandy
cm: testcase about cm
pd: testcase about pd
(addopts参数可以更改默认命令行选项)
标记好之后,可以使用pytest --markers再次查看,确认是否添加成功
最上面的就是新增写入到pytest.ini的配置了,例如:
pytest --markers
@pytest.mark.p0: level p0
@pytest.mark.p1: level p1
@pytest.mark.p2: level p2
@pytest.mark.dong: testcase created by dong
@pytest.mark.mandy: testcase created by mandy
@pytest.mark.cm: testcase about cm
@pytest.mark.pd: testcase about pd
@pytest.mark.no_cover: disable coverage for this test.
.
.
.
2.运行带有标记的用例:
pytest -m p0
仅运行用@pytest.mark.p0 装饰器修饰的所有测试用例
如果要运行多个标识,可使用表达式
pytest -m "p1 or p2" #运行有p1标识或p2标识用例
pytest -m "p1 and p2" #运行有p1和p2标识的用例
pytest -m "not p1" #运行除了p1之外的标识的用例
pytest -m "p1 and not p2" #运行有p1和没有p2标识的用例
注意:-m后面不能带' '号(单引号),只能带" "(双引号),不然识别不到
总结
可以使用@pytest.mark装饰器来给用例分类
运行的时候使用 -m,来运行某个或某些分类(按照用例的等级分类来执行测试用例)
-m参数支持python表达式
1)用or实现多选的效果
2)用not实现反选的效果
3)也可以根据用例名称进行筛选 -k(-k 匹配的对应的测试名用例)
例:pytest -k p1
@pytest.mark.parametrize(argname, argvalues)装饰器的方式进行参数化
@pytest.mark.parametrize实现测试用例参数化;还可以在类或模块上使用参数化标记,也可以在参数化中标记单个测试实例
parametrize的第一参数是用逗号分隔的字符串列表 ;第二个参数是一个数值列表,相当于传入一个数值列表,pytest会轮流对每个数值做测试,并分别报告每个测试的结果
a.用标记函数参数化,传入单个参数,pytest.mark.parametrize("参数名",lists)
b.采用标记函数传入多个参数,如:pytest.mark.parametrize("para1, para2", [(p1_data_0, p2_data_0), (p1_data_1, p2_data_1),...])
c.若要获得多个参数化参数的所有组合,可以堆叠参数化装饰器,例如:
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
d.可以在参数化 标记单个测试实例,例如使用内置的mark.xfail
@pytest.mark.parametrize("test_input,expected",
[("3+5", 8),
("2+4", 6),
pytest.param("6 * 9", 42,marks=pytest.mark.xfail),
])
@pytest.mark.usefixtures(fixturename1, fixturename2, ...)
@pytest.mark.usefixtures 标记使用指定的fixtures(一般是测试准备及清理方法)
我们可以用conftest.py 文件中存放参数化数据和函数,可作用于模块内的所有测试用例,模块下的用例执行时,会自动读取conftest.py文件中的数据
# content of conftest.py
import pytest
import tempfile
import os
@pytest.fixture()
def sign1():
print("Test case p0")
并通过usefixtures标记在测试用例前声明:
@pytest.mark.usefixtures("sign1")
这样标记了之后,sign每次执行测试用例 都会一起执行夹具,就像为测试用例指定一个“sign”函数参数一样
还可以指定多个:@pytest.mark.usefixtures(fixturename1, fixturename2, ...):
@pytest.mark.usefixtures("sign1","sign2")
注意:应用于fixture 函数时,该标记无效
@pytest.mark.skip @pytest.mark.skipif:跳过测试用例
描述:skip和skipif可以标记无法在某些平台上运行的测试功能,或者您希望失败的测试功能。使用skipif可以给跳过的测试添加理由和条件。
skip 意味着您希望只有在满足某些条件时测试才能通过,否则pytest应该跳过运行测试。常见的例子是跳过非Windows平台上的仅限Windows的测试,或者跳过依赖于当前不可用的外部资源(例如数据库)的测试。
a.无条件跳过测试函数(可以添加跳过的条件和理由说明)
@pytest.mark.skip(condition,reason="原因")
b.有条件的跳过某个测试 skipif
@pytest.mark.skipif(有效的Python表达式)
直接运行用例看不到跳过用例的原因,这时候可以使用 -rs
pytest -rs test_skip.py
c.跳过某测试模块 importskip
@pytest.importskip("模块名")
注意:使用skip和skipif标记,测试用例会直接跳过,而不会被执行
@pytest.mark.xfail:将测试标记为预期失败
1.使用mark.xfail 标记为预期测试失败:
@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False)
- condition(bool或str) - 将测试函数标记为xfail(True/False或条件字符串)的 条件。
- reason(str) - 测试函数标记为xfail的原因。
- 引发(异常) - 期望由测试函数引发的异常子类; 其他例外将无法通过测试。
- run(bool) - 如果实际应该执行测试功能。如果False,该函数将始终为xfail并且不会被执行(如果函数是segfaulting则很有用)
例如:
@pytest.mark.xfail
def test_function():
...
标记为xfail 的用例依旧会执行,但失败时不会报告任何回溯。相反,终端报告将把它列在“预期失败”中。 (XFAIL )或“意外通过” (XPASS )部分。
x表示XFAIL,预期失败,实际也失败
X表示XPASS,预期失败,实际运行没有失败
2.也可从测试用例 中 将测试标记为 xfail:
def test_02(self, login):
result = login
print("case2: %s" % result)
if not result:
pytest.xfail("xfail")
如果满足了标记的条件,就会无条件地将test_02标记为xfail。需要注意,之后其他调用了已被标记为 xfail的用例(test_02)也不会执行了,与直接mark不同,这是因为它是通过引发一个已知的异常在内部实现的。
还可以可以通过命令行指定运行标记了xfail的用例:
pytest --runxfail
可以强制运行和报告被标记为 xfail的测试用例。(通过 pytest.xfail来实现标记为xfail的用例不会执行)
@pytest.mark.flaky:失败重跑用例
标记失败重跑次数@pytest.mark.flaky(reruns=5, reruns_delay=1) (需安装pytest-rerunfailures)
- 最多失败重跑5次 & 如果失败则延迟1秒后重跑(可以不传)
- 或命令$pytest --reruns 5 --reruns-delay 1
先安装pytest-rerunfailures
pip install pytest-rerunfailures
在测试用例前使用标记flaky:
@pytest.mark.flaky(reruns=1, reruns_delay=0)
其他mark
- 标记用例执行顺序pytest.mark.run(order=1) (需安装pytest-ordering)
- 标记超时时间 @pytest.mark.timeout(60) (需安装pytest-timeout)
- 或命令$pytest --timeout=300
- 标记类中用例按定义(书写)顺序执行(某一条失败则后面的用例不会执行) @pytest.mark.incremental
- 为标记的测试项添加警告过滤器 @pytest.mark.filterwarnings()
@pytest.mark.tryfirst:
@pytest.mark.trylast: