Pytest骨灰级教学(三)用例标记和测试执行
前面介绍了pytest的前后置方法和fixture机制,这个章节主要介绍pytest中的标记机制和用例执行的方法。pytest可以通过标记将数据传入于测试函数中,也可以通过标记对执行的用例做筛选,接下来直接进入正题。
一、pytest中内置的标记
pytest标记使用需要通过pytest.mark.标记来使用,pytest中为应对各种测试场景也内置了很多的标记。
1、pytest.mark.parametrize:用例参数化的标记
通过parametrize可以将用例数据和用例执行的逻辑代码分离,并实现根据用例数据,自动生成测试用例。
test_demo5.py:
import pytest
@pytest.mark.parametrize('item', [11, 55, 66])
# 这里传入的参数名要和parametrize中的‘item’相同,传入的列表中的元素会依次传入测试用例中,列表中有几个元素,就生成几个测试用例
def test_demo(item):
assert item > 50
运行结果如下:
2、pytest.mark.skip:跳过用例执行
通过skip装饰的用例,在执行的时候会无条件跳过,参数reason:跳过测试函数的原因。
test_demo5.py:
import pytest
# 不写跳过原因
@pytest.mark.skip()
@pytest.mark.parametrize('item', [11, 77, 20])
def test_demo1(item):
assert item > 50
# 写跳过原因
@pytest.mark.skip(reason='不需要执行')
@pytest.mark.parametrize('item', [11, 77, 20])
def test_demo2(item):
assert item > 50
运行结果如下:
3、pytest.mark.skipif:根据条件跳过用例skipif可以根据条件来决定是否跳过用例的执行, 如果条件为True则跳过测试函数执行。参数 :condition ——跳过的条件;参数 : reason ——跳过的原因
test_demo5.py:
import pytest
a = 30
@pytest.mark.skipif(a > 20, reason='a大于20了,所以不执行')
@pytest.mark.parametrize('item', [11, 55, 66])
def test_demo(item):
assert item > 50
运行结果如下:
4、pytest.mark.xfail:标记预期失败的用例xfail可以将测试函数标记为预期执行失败的用例。
参数 :condition — 将测试函数标记为 xfail 的条件(True/False )
参数 : reason — 测试函数被标记为 xfail 的原因
参数 : raises — 预期失败的异常类型
参数 : run — 是否应该实际执行测试函数。如果False,该函数将始终 xfail 并且不会被执行 。
参数 : strict — 严格模式(True/False )
test_demo5.py:
import pytest
a = 30
@pytest.mark.parametrize('item', [11, 55, 66])
@pytest.mark.xfail(a > 20,reason='大于20了,预期失败' raises=AssertionError )
def test_demo(item)
assert item > 50
运行结果如下:
5、pytest.mark.usefixtures:给测试类或模块设置测试夹具usefixtures标记一般用于给测试类下面的测试用例方法统一设置测试夹具。
test_demo5.py:
# TestDemo这个测试类的所有测试用例均执行my_fixture这个夹具
@pytest.mark.usefixtures('my_fixture')
class TestDemo:
# 函数用例 指定测试夹具
def test_01(self):
print('----测试用例:test_01------')
# 函数用例 指定测试夹具
def test_02(self):
print('----测试用例:test_02------')
二、自定义标记
pytest支持通过pytest.ini文件注册自定义的标记。以满足执行用例时,通过标记对用例进行筛选;也可以使用pyproject.toml来注册自定义标记种类,文件内容如下:
[tool.pytest.ini_options]
markers = [
"smoke: 冒烟测试用例",
"login: 登录模块测试用例",
"order: 订单模块用例",
"serial",
]
ps: pyproject.toml是pytest6.0的新功能
1、标记函数
如果这个标记是在函数上,那么就代表着函数属于标记的筛选用例。
@pytest.mark.smoke
def test_demo():
pass
2、标记类
如果标记在类上,那么整个类下的所有函数都属于筛选用例。
# 方式一:直接类上面打标记
@pytest.mark.smoke
class TestClass1:
def test_demo1(self):
assert 10 > 20
# 方式二:通过类属性pytestmark,可以同时添加多个标记
class TestClass2:
pytestmarks = [pytest.mark.smoke, pytest.mark.order]
def test_demo2(self):
assert 10 < 20
3、标记用例表达式
3.1、通过单个标记筛选:pytest -m '标签名' eg:pytest -m "smoke"
3.2、同时选中多个标记:pytest -m "标记1 or 标记2" eg:pytest -m "smoke or login"; eg:pytest -m "smoke and login"; eg:pytest -m "smoke and not login" 可以非常灵活的自由选取筛选想运行的标记用例
三、常用的第三方插件
1.用例按顺序执行:pytest-ordering
前面文章举的例子用例执行顺序都是Pytest内部决定的,Pytest默认会按字母顺序执行。当遇到一些有上下文依赖关系的用例或者我们想指定用例执行顺序时,可以下载pytest-ordering,然后在测试方法上加上对应装饰器来指定用例执行顺序。具体如下:
下载安装:pip install pytest-ordering
import pytest
class TestDemo1:
# 最后一个执行
@pytest.mark.run(order=-1)
def test_01(self):
print('----测试用例:test_01------')
assert 5 == 5
@pytest.mark.run(order=2)
def test_02(self):
print('----测试用例:test_02------')
assert 6 == 6
class TestDemo2:
@pytest.mark.run(order=1)
def test_03(self):
print('----测试用例:test_03------')
assert 5 == 7
运行结果如下: 
从红框中可以清晰看出用例的执行顺序。
2.失败重试:pytest-rerunfailures
下载安装:pip install pytest-rerunfailures
运行时指定:pytest -v -s 文件名.py --reruns 5 --reruns-delay 1 每次等1秒 重试5次
也可在测试方法上指定:@pytest.mark.flaky(reruns=5,reruns_delay=1) 每次等1秒 重试5次
import pytest
class TestDemo2:
@pytest.mark.flaky(reruns=3, reruns_delay=1)
def test_03(self):
print('----测试用例:test_03------')
assert 5 == 7
运行结果如下: 
3.断言报错后依然执行,多重断言: pytest-assume
一个测试用例中可以有多个assert断言,在执行测试用例时,断言assert一旦失败了后面的代码就不会执行了。pytest-assume可以支持断言失败后面的代码继续执行,但是需要改下断言方式。具体如下:
下载安装:pip install pytest-assume
import pytest
def test_assume():
print('登录操作')
pytest.assume(1 == 2)
print('搜索操作')
pytest.assume(2 == 2)
print('加购操作')
pytest.assume(3 == 2)
4.多线程并行与分布式执行: pytest-xdist
Pytest也支持多线程及分布式执行。如:10000个用例每个用例执行需1分钟,那就需要执行10000分钟,当把单线程改成多线程来执行时可能只需要10分钟,节省了大量时间。我们可以用Pytest分布式执行插件pytest-xdist来实现多个CPU或主机执行。具体如下:
下载安装:pip install pytest-xdist
使用命令运行:pytest -v -s -n 5 文件名.py ----执行5个线程,多个CPU并行执行用例
注意:使用pytest-xdist的前提条件是用例之间都是独立的,没有先后顺序,随机都能执行,可重复运行不影响其他用例。
5、用例依赖:pytest-dependency
使用该插件可以标记一个测试用例作为其他测试用例的依赖,当依赖项执行失败时,那些依赖它的用例将会被跳过。
下载安装:pip install pytest-dependency
依赖项失败时:
import pytest
class TestDemo1:
# 列表中的依赖项可以是多个,即可以依赖多个测试用例,只要存在一个依赖失败,那么test_02就被跳过;这里有个坑,需要写全类名
@pytest.mark.dependency(depends=['TestDemo2::test_03'])
def test_02(self):
print('----测试用例:test_02------')
assert 5 == 5
class TestDemo2:
@pytest.mark.run(order=1)
@pytest.mark.dependency()
def test_03(self):
print('----测试用例:test_03------')
assert 7 == 8
运行结果如下:
依赖项成功时:
import pytest
class TestDemo1:
# 列表中的依赖项可以是多个,即可以依赖多个测试用例,只要存在一个依赖失败,那么test_02就被跳过;这里有个坑,需要写全类名
@pytest.mark.dependency(depends=['TestDemo2::test_03'])
def test_02(self):
print('----测试用例:test_02------')
assert 5 == 5
class TestDemo2:
@pytest.mark.run(order=1)
@pytest.mark.dependency()
def test_03(self):
print('----测试用例:test_03------')
assert 7 == 7
运行结果如下:
6、测试进度可视化:pytest-sugar
pytest-sugar改变了Pytest的默认外观,增加了一个进度条,并立即显示失败的测试。它不需要配置,只需下载安装pytest-sugar,用pytest运行测试,可获得更漂亮,更有用的输出。没啥卵用,我试了一下就uninstall了,有兴趣的话你们可以试试。
7、重复测试直到失败为止:pytest-repeat
当一个测试用例出现偶发性BUG时,可以使用pytest-repeat进行重复测试直到失败为止。具体如下:
下载安装:pip install pytest-repeat
想在代码中将某些测试用例标记为执行重复多次直到失败为止,可以使用:@pytest.mark.repeat(5)
另外:
allure的命令行参数
pytest.main()中也可以使用allure的命令参数进行测试用例的指定和执行。
--allure-severities=SEVERITIES_SET
Comma-separated list of severity names. Tests only
with these severities will be run. Possible values
are: blocker, critical, normal, minor, trivial.
--allure-epics=EPICS_SET
Comma-separated list of epic names. Run tests that
have at least one of the specified feature labels.
--allure-features=FEATURES_SET
Comma-separated list of feature names. Run tests that
have at least one of the specified feature labels.
--allure-stories=STORIES_SET
Comma-separated list of story names. Run tests that
have at least one of the specified story labels.
--allure-link-pattern=LINK_TYPE:LINK_PATTERN
Url pattern for link type. Allows short links in test,
like 'issue-1'. Text will be formatted to full url
with python str.format().
例如:
pytest.main(['--alluredir=reports', '--allure-features=xxxfeature测试用例', '-sv'])
四、通过pytest.ini或者pyproject.toml来配置执行测试用例
pytest.ini和pyproject.toml都可以作为pytest框架的配置文件,不过pytest.ini是主配置文件,它的优先级高于pyproject.toml,上面我使用过了pyproject.toml,这里我使用pytest.ini。
pytest.ini是pytest单元测试框架的核心配置文件,一般放在项目的根目录,编码格式必须是ANSI,可以使用notepad++来修改编码格式,它可以改变pytest的行为,比如测试用例的执行规则等
[pytest]
addopts = -vs #命令行的参数,用空格分隔
testpaths = ./test_cases #测试用例的路径
python_files = test_*.py #测试模块名的规则
python_classes = Test* #测试类的规则
python_functions = test #测试方法函数的规则
markers =
smoke: 冒烟用例
login: 登录用例

浙公网安备 33010602011771号