二、Pytest Marks 详解

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)

  • conditionboolstr) - 将测试函数标记为xfail(True/False或条件字符串)的 条件
  • reasonstr) - 测试函数标记为xfail的原因。
  • 引发异常) - 期望由测试函数引发的异常子类; 其他例外将无法通过测试。
  • runbool) - 如果实际应该执行测试功能。如果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)

  1. 最多失败重跑5次 & 如果失败则延迟1秒后重跑(可以不传)
  2. 或命令$pytest --reruns 5 --reruns-delay 1

先安装pytest-rerunfailures

pip install pytest-rerunfailures

在测试用例前使用标记flaky:

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

 

其他mark
  1. 标记用例执行顺序pytest.mark.run(order=1) (需安装pytest-ordering)
  2. 标记超时时间 @pytest.mark.timeout(60) (需安装pytest-timeout)
    1. 或命令$pytest --timeout=300
  3. 标记类中用例按定义(书写)顺序执行(某一条失败则后面的用例不会执行) @pytest.mark.incremental
  4. 为标记的测试项添加警告过滤器 @pytest.mark.filterwarnings()

@pytest.mark.tryfirst: 

@pytest.mark.trylast: 

 

posted @ 2020-06-17 15:33  hongliangsam  阅读(2089)  评论(0编辑  收藏  举报