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,或扫描下面的二维码添加关注:

posted @ 2025-06-15 19:47  Surpassme  阅读(119)  评论(0)    收藏  举报