06-Pytest 插件
6. 插件
Pytest自带的功能已经非常强大,通过添加插件可以让其变得更加强大。Pytest的代码结构适合定制的扩展插件,可以借助hook函数来实现。把fixture函数或hook函数添加到conftest.py文件中,就已经创建了一个本地的conftest插件,也可以很容易把这些conftest.py文件转换为可安装的插件,与其他人分享。
6.1 搜索插件
一般安装插件主要是官网 https://pypi.org/ 中以pytest作为关键字搜索或者去Pytest的Github仓库查找,地址为 https://github.com/pytest-dev/
另外,在Pytest官网也有相应介绍如何安装和使用插件的文档 https://docs.pytest.org/en/latest/how-to/plugins.html
6.2 安装插件
安装Pytest插件和安装Python包一样使用pip install即可。例如:
# 安装最新版本的插件
pip install pytest-cov
# 安装指定版本的插件
pip install pytest-cov==6.2.1
# 离线安装插件
pip install pytest_cov-6.2.1.tar.gz
pip install pytest_cov-6.2.1-py3-none-any.whl
6.3 编写插件
使用第三方的插件可以做到开箱即用,非常节省时间。但每个测试任务并不是都有第三方插件能满足自身要求的,因此在某些情况下,就需要自己编写插件。
插件可以包含改变Pytest行为的hook函数。而编写插件就是使用插件改变Pytest的运行方式。Pytest中提供的hook函数可查阅官方文档https://docs.pytest.org/en/latest/reference/reference.html#hooks。
以下将演示创建一个插件,主要添加以下功能:
- 增加一些额外的输出信息
- 修改用例运行失败的默认状态标识
- 提供一个新的参数来打开该功能
示例代码如下所示:
# @IDE: PyCharm
# @Project: PyCharmProjects
# @File: test_api_exceptions.py
# @Time 2025-06-14 15:46
# @Author: Surpass Lee
# @E-mail: surpassmebyme@gmail.com
import pytest
def add(a:int,b:int)->int:
return a+b
class TestAdd():
"""test add sample"""
@pytest.mark.parametrize("a,b,expect",[(1,2,3),(2,4,6),(4,5,8),("1","2","12")])
def test_add_1(self,a,b,expect):
assert add(a,b) == expect
运行结果如下所示:
$ pytest --tb=no
============================== test session starts ===============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-06
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 4 items
test_api_exceptions.py ..F. [100%]
============================ short test summary info =============================
FAILED test_api_exceptions.py::TestAdd::test_add_1[4-5-8] - assert 9 == 8
========================== 1 failed, 3 passed in 0.02s ===========================
1.添加输出额外信息
在conftest.py添加以下代码:
def pytest_report_header(config):
"""在终端输出报告添加额外信息
参考URL:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_report_header
"""
return "给Pytest终端输出报告添加额外信息"
其中 pytest_report_header 的源码定义为:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_report_header
运行输出结果如下所示:
$ pytest --tb=no
============================== test session starts ===============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
给Pytest终端输出报告添加额外信息
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-06
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 4 items
test_api_exceptions.py ..F. [100%]
============================ short test summary info =============================
FAILED test_api_exceptions.py::TestAdd::test_add_1[4-5-8] - assert 9 == 8
========================== 1 failed, 3 passed in 0.01s ===========================
在以上示例中添加的信息,在实际测试任务中并没有太大意义,但你可以添加一些有意义的信息,例如用户名、当前测试的版本信息等。
2.修改用例运行失败的默认状态标识
def pytest_report_teststatus(report,config):
"""
修改默认输出状态
参考URL:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_report_teststatus
:param report:
:return:
"""
if report.when=="call" and report.failed:
return (report.outcome,"失败","用例运行失败,待检查")
运行输出结果如下所示:
$ pytest --tb=no
============================== test session starts ===============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
给Pytest终端输出报告添加额外信息
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-06
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 4 items
test_api_exceptions.py ..失败. [100%]
============================ short test summary info =============================
用例运行失败,待检查 test_api_exceptions.py::TestAdd::test_add_1[4-5-8] - assert 9 == 8
========================== 1 failed, 3 passed in 0.02s ===========================
3. 提供一个新的参数来打开该功能
def pytest_addoption(parser):
"""
添加自定义参数
参考URL:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_addoption
:param parser:
:return:
"""
group = parser.getgroup("custom-params-sample")
group.addoption("--custom-params-sample",action="store_true",default=None,help="--custom-params-sample:测试自定义参数")
def pytest_report_header(config):
"""在终端输出报告添加额外信息
参考URL:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_report_header
"""
if config.getoption(name="--custom-params-sample"):
return "给Pytest终端输出报告添加额外信息"
def pytest_report_teststatus(report,config):
"""
修改默认输出状态
参考URL:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_report_teststatus
:param report:
:return:
"""
if config.getoption(name="--custom-params-sample"):
if report.when=="call" and report.failed:
return (report.outcome,"失败","用例运行失败,待检查")
未添加参数--custom-params-sample是,运行结果如下所示:
$ pytest --tb=no
============================ test session starts ============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-06
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 4 items
test_api_exceptions.py ..F. [100%]
============================ short test summary info ============================
FAILED test_api_exceptions.py::TestAdd::test_add_1[4-5-8] - assert 9 == 8
============================= 1 failed, 3 passed in 0.02s ============================
添加参数--custom-params-sample是,运行结果如下所示:
$ pytest --tb=no --custom-params-sample
============================ test session starts ============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
给Pytest终端输出报告添加额外信息
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-06
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 4 items
test_api_exceptions.py ..失败. [100%]
============================ short test summary info ============================
用例运行失败,待检查 test_api_exceptions.py::TestAdd::test_add_1[4-5-8] - assert 9 == 8
============================ 1 failed, 3 passed in 0.01s ============================
查看Pytest帮助文档输出如下所示:
$ pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:
file_or_dir
...
reporting:
--alluredir=DIR Generate Allure report in the specified directory (may not exist)
--clean-alluredir Clean alluredir folder if it exists
--allure-no-capture Do not attach pytest captured logging/stdout/stderr to report
--inversion=INVERSION
Run tests not in testplan
custom-params-sample:
--custom-params-sample
--custom-params-sample:测试自定义参数
6.4 案例实战
如果要对用例进行筛选分类,一般是在编写用例的时候使用@pytest.mark来进行预定义标签,然后在运行的使用pytest -m 进行筛选运行,这也是现行非常推荐的做法。既然pytest提供了非常丰富的插件系统,那么是不是我们也可以自定义一个hook来修改用例分类的默认方法,比例通过Python里的docstring来进行分类?示例如下所示:
1.编写hook函数
from pytest import Item,Config,Parser
def pytest_report_header(config:Config):
if config.getoption(name="--smoke"):
return "筛选 smoke 测试用例"
def pytest_addoption(parser:Parser):
"""
添加一个参数选项
:param parser:
:return:
"""
group = parser.getgroup("smoke")
group.addoption( "--smoke",action="store_true",default=None,help="筛选smoke测试用例")
def pytest_collection_modifyitems(config:Config, items:list[Item]):
"""
参考URL: https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html#pytest_collection_modifyitems
:param config:
:param items: 代表pytest收集到的测试用例列表
:return:
"""
if config.getoption(name="--smoke"):
new_case_item_list=[]
for item in items:
# 判断docstring中是否存在且是非包含#smoke字段
if item.function.__doc__ and "#smoke" in item.function.__doc__.lower():
new_case_item_list.append(item)
# 将筛选后的用例列表传回给Pytest
items[:] = new_case_item_list
2.编写测试脚本
# @IDE: PyCharm
# @Project: PyCharmProjects
# @File: testDocstringFilter
# @Time 2025-06-14 20:00
# @Author: Surpass Lee
# @E-mail: surpassmebyme@gmail.com
import pytest
class TestDocString():
@pytest.mark.Smoke
def test_smoke_1(self):
print(f"运行测试用途:{self.test_smoke_1.__name__}")
def test_smoke_2(self):
"""
#smoke
:return:
"""
print(f"运行测试用途:{self.test_smoke_2.__name__}")
@pytest.mark.Smoke
def test_smoke_3(self):
"""
#smoke
:return:
"""
print(f"运行测试用途:{self.test_smoke_3.__name__}")
@pytest.mark.P1
def test_pri_1(self):
print(f"运行测试用途:{self.test_pri_1.__name__}")
@pytest.mark.P2
def test_pri_2(self):
print(f"运行测试用途:{self.test_pri_2.__name__}")
@pytest.mark.P3
def test_pri_3(self):
print(f"运行测试用途:{self.test_pri_3.__name__}")
@pytest.mark.Regression
def test_regression_1(self):
print(f"运行测试用途:{self.test_regression_1.__name__}")
不添加参数smoke参数,运行结果如下所示:
$ pytest --collect-only
=========================== test session starts ============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\Pytest\03-codes\Content-07
configfile: pytest.ini
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 7 items
<Dir Content-07>
<Module testDocstringFilter.py>
<Class TestDocString>
<Function test_smoke_1>
<Function test_smoke_2>
<Function test_smoke_3>
<Function test_pri_1>
<Function test_pri_2>
<Function test_pri_3>
<Function test_regression_1>
======================== 7 tests collected in 0.01s ========================
使用pytest -m参数,运行结果如下所示:
$ pytest --collect-only -m "Smoke"
=========================== test session starts ============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\Pytest\03-codes\Content-07
configfile: pytest.ini
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 7 items / 5 deselected / 2 selected
<Dir Content-07>
<Module testDocstringFilter.py>
<Class TestDocString>
<Function test_smoke_1>
<Function test_smoke_3>
=============== 2/7 tests collected (5 deselected) in 0.02s ================
使用pytest --smoke参数,运行结果如下所示:
$ pytest --collect-only --smoke
=========================== test session starts ============================
platform win32 -- Python 3.12.8, pytest-8.3.5, pluggy-1.5.0
筛选 smoke 测试用例
rootdir: C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\Pytest\03-codes\Content-07
configfile: pytest.ini
plugins: allure-pytest-2.13.5, anyio-4.7.0
collected 7 items
<Dir Content-07>
<Module testDocstringFilter.py>
<Class TestDocString>
<Function test_smoke_2>
<Function test_smoke_3>
======================== 7 tests collected in 0.01s ========================
6.5 插件推荐
Pytest存在着非常丰富的插件,以满足不同的测试需求。官方提供的插件列表可查阅网址:https://docs.pytest.org/en/latest/reference/plugin_list.html
这里推荐一些比较常用的插件
| 插件名称 | 主要功能 | Pypi地址 |
|---|---|---|
| pytest-repeat | 用于重复运行某个或某些测试用例 | https://pypi.org/project/pytest-repeat/ |
| pytest-cov | 用于计算和统计代码覆盖率 | https://pypi.org/project/pytest-cov/ |
| pytest-xdist | 用于并行运行测试 | https://pypi.org/project/pytest-xdist/ |
| pytest-timeout | 为测试设置超时时间 | https://pypi.org/project/pytest-timeout/ |
| pytest-sugar | 添加色彩和进度条 | https://pypi.org/project/pytest-sugar/ |
| pytest-html | 生成HTML测试报告 | https://pypi.org/project/pytest-html/ |
| pytest-django | 测试Django应用 | https://pypi.org/project/pytest-django/ |
本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注:

作者: Surpassme
来源: http://www.jianshu.com/u/28161b7c9995/
http://www.cnblogs.com/surpassme/
声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接 ,否则保留追究法律责任的权利。如有问题,可发送邮件 联系。让我们尊重原创者版权,共同营造良好的IT朋友圈。

浙公网安备 33010602011771号