深入解析 Pytest 钩子函数及二次开发过程

news2024/12/28 21:05:03

关注开源优测不迷路

大数据测试过程、策略及挑战

测试框架原理,构建成功的基石

在自动化测试工作之前,你应该知道的10条建议

在自动化测试中,重要的不是工具

在 Pytest 测试框架中,钩子函数(Hooks)是一种强大的扩展机制,它允许开发者在测试执行的不同阶段插入自定义代码,从而实现对测试过程的精细控制和个性化定制。钩子函数能够与 Pytest 的核心功能无缝集成,为各种复杂的测试需求提供灵活的解决方案。无论是在测试环境的初始化、测试结果的处理,还是在测试用例的管理与执行控制等方面,钩子函数都发挥着至关重要的作用。

一、Pytest 钩子函数概述

1.1 钩子函数的概念与作用

钩子函数本质上是 Pytest 框架提供的一系列回调接口,它们在测试执行的特定时间点被自动调用。这些时间点涵盖了测试过程的各个阶段,从测试用例的收集、执行前的准备,到测试执行后的清理和结果报告等。通过实现这些钩子函数,开发者可以在不修改 Pytest 核心代码的前提下,向测试框架注入自定义的行为逻辑,使其适应不同项目的特定需求。


1.2 钩子函数的分类

Pytest 的钩子函数可以根据其作用的阶段和功能进行分类,常见的分类包括但不限于以下几种:

  • 测试用例收集相关钩子函数:这些钩子函数在 Pytest 收集测试用例的过程中被触发,开发者可以利用它们对收集到的测试用例进行筛选、排序或修改。例如,pytest_collection_modifyitems钩子函数允许开发者在测试用例收集完成后,对测试用例列表进行自定义操作,如根据标记(mark)过滤某些测试用例,或者重新调整测试用例的执行顺序。

  • 测试执行环境相关钩子函数:主要用于在测试执行前和执行后对测试环境进行配置和清理操作。比如pytest_sessionstart钩子函数在测试会话开始时被调用,开发者可以在这个钩子函数中进行一次性的全局初始化操作,如创建数据库连接、初始化日志系统等;而pytest_sessionfinish钩子函数则在测试会话结束时被触发,可用于关闭数据库连接、清理临时文件等资源释放操作。

  • 测试结果处理相关钩子函数:在测试执行完成后,用于处理和报告测试结果。pytest_runtest_makereport钩子函数可以获取每个测试用例的执行结果信息,开发者可以根据这些信息进行自定义的结果处理,如生成更详细的测试报告、将测试结果发送到特定的监控系统等。

  • 其他钩子函数:除了上述主要类型外,Pytest 还提供了许多其他类型的钩子函数,用于处理诸如命令行参数解析、插件加载、测试执行过程中的异常处理等各种不同的场景。这些钩子函数共同构成了一个丰富而灵活的扩展体系,使开发者能够全面地定制 Pytest 的行为。


二、常用 Pytest 钩子函数详解


2.1 pytest_configure钩子函数

  1. 函数功能
    pytest_configure钩子函数在 Pytest 开始收集测试用例之前被调用,它主要用于对整个测试运行环境进行全局配置。在这个钩子函数中,开发者可以访问和修改 Pytest 的配置对象(config),通过设置各种配置选项来定制测试框架的行为。例如,可以添加自定义的命令行选项、配置测试结果报告的格式和输出路径、注册自定义的标记(mark)等。

  2. 使用示例
    以下是一个简单的示例,展示了如何在pytest_configure钩子函数中添加一个自定义的命令行选项--my-option,并在测试中使用这个选项的值:

# conftest.py文件




def pytest_configure(config):
    # 添加自定义命令行选项
    config.addinivalue_line(
        "markers", "my_marker: 用于标记特定的测试用例"
    )
    config.addoption(
        "--my-option", action="store", default="default_value", help="这是一个自定义选项"
    )


def pytest_collection_modifyitems(items):
    # 遍历所有测试用例,根据自定义标记进行筛选
    selected_items = []
    deselected_items = []
    for item in items:
        if "my_marker" in item.keywords:
            selected_items.append(item)
        else:
            deselected_items.append(item)
    items[:] = selected_items

在上述示例中,首先在pytest_configure钩子函数中添加了一个名为my_marker的自定义标记,以及一个名为--my-option的命令行选项。然后,在pytest_collection_modifyitems钩子函数(用于在测试用例收集完成后对其进行修改)中,根据是否存在my_marker标记来筛选测试用例。在实际的测试脚本中,可以使用@pytest.mark.my_marker来标记需要执行的测试用例,并通过pytestconfig对象(通过pytest夹具获取)来访问--my-option选项的值。


2.2 pytest_collection_modifyitems钩子函数

  1. 函数功能
    pytest_collection_modifyitems钩子函数在 Pytest 完成测试用例收集后、但在测试用例执行之前被调用。它提供了一个机会,让开发者可以对收集到的测试用例列表进行最后的修改和调整。这包括但不限于根据特定条件筛选测试用例、重新排序测试用例、为测试用例添加额外的属性或标记等操作。

  2. 使用示例
    假设我们有一个项目,其中包含了多个测试模块,每个模块中又有多个测试用例。现在我们希望在某些情况下,只执行特定模块中的测试用例,或者按照特定的顺序执行测试用例。以下是一个示例,展示了如何使用pytest_collection_modifyitems钩子函数来实现这些功能:

# conftest.py文件




def pytest_collection_modifyitems(items):
    # 按照模块名对测试用例进行排序
    items.sort(key=lambda item: item.module.__name__)


    # 筛选出特定模块中的测试用例
    selected_items = []
    deselected_items = []
    for item in items:
        if item.module.__name__.startswith("test_specific_module"):
            selected_items.append(item)
        else:
            deselected_items.append(item)
    items[:] = selected_items

在这个示例中,首先通过sort方法按照测试用例所在模块的名称对测试用例列表进行排序。然后,通过遍历测试用例列表,筛选出模块名以test_specific_module开头的测试用例,并将其保留在items列表中,其他测试用例则被移除。这样,在执行测试时,只会执行符合条件的特定模块中的测试用例,并且这些测试用例会按照模块名的顺序依次执行。


2.3 pytest_sessionstartpytest_sessionfinish钩子函数

2.3.1 函数功能

  • pytest_sessionstart钩子函数在测试会话开始时被调用,它主要用于执行一些一次性的全局初始化操作。这些操作通常与整个测试运行环境相关,例如创建共享的测试资源(如数据库连接池、日志文件句柄等)、初始化全局变量或配置对象等。

  • pytest_sessionfinish钩子函数则在测试会话结束时被触发,其主要职责是进行资源清理和收尾工作。这包括关闭在测试会话开始时打开的各种资源(如数据库连接、文件句柄等)、保存测试结果或执行其他与测试结束相关的操作(如生成测试报告、发送通知等)。

2.3.2 使用示例
以下是一个简单的示例,展示了如何在pytest_sessionstartpytest_sessionfinish钩子函数中进行数据库连接的初始化和关闭操作:

# conftest.py文件




import pytest
import sqlite3


@pytest.fixture(scope='session')
def database_connection():
    # 在pytest_sessionstart钩子函数中创建数据库连接
    connection = sqlite3.connect('test.db')
    yield connection
    # 在pytest_sessionfinish钩子函数中关闭数据库连接
    connection.close()


def pytest_sessionstart(session):
    print("测试会话开始,正在进行初始化操作...")
    # 可以在这里进行其他全局初始化操作,如创建日志文件等


def pytest_sessionfinish(session, exitstatus):
    print("测试会话结束,正在进行清理操作...")
    # 可以在这里进行其他清理操作,如删除临时文件等

在上述示例中,定义了一个名为database_connection的测试夹具,其作用域为会话级。在pytest_sessionstart钩子函数中,创建了一个 SQLite 数据库连接,并将其作为测试夹具的值返回。在测试用例中,可以使用这个测试夹具来获取数据库连接对象,进行数据库相关的操作。当测试会话结束时,pytest_sessionfinish钩子函数会被调用,关闭之前创建的数据库连接,确保资源得到正确释放。


2.4pytest_runtest_makereport钩子函数

2.4.1 函数功能
pytest_runtest_makereport钩子函数在每个测试用例执行完成后被调用,它负责生成测试用例的执行结果报告。这个钩子函数提供了详细的测试用例执行信息,包括测试用例的名称、所在模块、执行时间、执行结果(通过、失败、跳过等)以及可能的异常信息等。开发者可以利用这些信息来实现自定义的测试结果处理逻辑,如生成更详细的测试报告、将测试结果上传到远程服务器进行分析等。

2.4.2 使用示例
以下是一个简单的示例,展示了如何使用pytest_runtest_makereport钩子函数来记录每个测试用例的执行时间,并将其添加到测试结果报告中:

# conftest.py文件




import time


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()


    start_time = getattr(item, "start_time", None)
    if start_time is not None:
        end_time = time.time()
        report.duration = end_time - start_time
        report.user_properties.append(("执行时间", report.duration))


    return report


def pytest_runtest_setup(item):
    item.start_time = time.time()

在这个示例中,首先定义了pytest_runtest_makereport钩子函数,并使用@pytest.hookimpl(hookwrapper=True)装饰器将其包装为一个钩子函数包装器。在钩子函数内部,获取了测试用例的执行结果报告,并计算了测试用例的执行时间(通过记录测试用例开始执行的时间start_time,并在测试用例执行完成后计算与当前时间的差值)。然后,将执行时间添加到测试结果报告的user_properties属性中,以便在后续的测试报告生成或结果处理中使用。同时,通过pytest_runtest_setup钩子函数在每个测试用例执行前记录其开始时间。


三、Pytest 钩子函数的二次开发过程

3.1 确定需求

在进行 Pytest 钩子函数的二次开发之前,首先需要明确项目的具体需求。这可能包括但不限于以下几个方面:

  • 定制测试环境配置:例如,根据项目的特定需求,在测试开始前自动配置特定的环境变量、创建或初始化特定的测试资源(如数据库连接、消息队列连接等)。

  • 优化测试用例执行流程:可能需要按照特定的规则对测试用例进行排序、筛选或分组执行,以提高测试效率或满足特定的测试覆盖要求。

  • 增强测试结果处理:如生成更详细、定制化的测试报告,将测试结果与其他系统(如缺陷管理系统、持续集成服务器等)进行集成,实现自动化的测试结果通知和分析。

  • 扩展测试框架功能:例如,添加对新的测试类型或技术的支持,如与特定的性能测试工具集成、实现分布式测试等。

3.2 选择合适的钩子函数

根据确定的需求,从 Pytest 提供的众多钩子函数中选择合适的钩子函数来实现自定义逻辑。这需要对钩子函数的功能和触发时机有深入的了解,确保所选的钩子函数能够在正确的时间点执行所需的操作。例如,如果需要在测试用例收集阶段进行筛选操作,那么pytest_collection_modifyitems钩子函数可能是一个合适的选择;如果要在测试执行后处理结果,则pytest_runtest_makereport钩子函数可能更符合需求。


3.3 编写钩子函数代码

在选定钩子函数后,就可以开始编写自定义的钩子函数代码了。以下是一些编写钩子函数代码的基本步骤和注意事项:

3.3.1 导入必要的模块和对象
根据钩子函数的功能需求,导入所需的 Python 模块和 Pytest 相关的对象。例如,如果需要操作测试用例对象,可能需要导入pytest.Item类;如果要处理测试结果,可能需要导入pytest.Report类等。

3.3.2 定义钩子函数
使用def关键字定义钩子函数,并按照 Pytest 钩子函数的命名规范和参数要求进行定义。钩子函数的参数通常包含与测试过程相关的信息,如测试用例对象、测试执行结果对象、配置对象等。例如,pytest_runtest_makereport钩子函数的定义如下:

def pytest_runtest_makereport(item, call):


    # 钩子函数代码逻辑

其中,item参数表示测试用例对象,包含了测试用例的各种属性(如名称、所在模块、标记等);call参数包含了测试用例执行的详细信息,如执行结果(call.excinfo在测试失败时包含异常信息)等。

3.3.3 实现自定义逻辑
在钩子函数内部,根据需求实现自定义的逻辑代码。这可能包括对测试用例对象的操作、对测试结果的处理、与外部系统的交互等。例如,在pytest_collection_modifyitems钩子函数中,可以通过遍历测试用例列表,根据特定条件修改测试用例的属性或筛选出符合要求的测试用例:

def pytest_collection_modifyitems(items):


    for item in items:
        if "特定标记" in item.keywords:
            item.add_marker(pytest.mark.skip(reason="根据需求跳过此测试用例"))

在这个例子中,遍历所有收集到的测试用例,如果测试用例包含 “特定标记”,则为其添加一个skip标记,使其在测试执行时被跳过。

3.3.4 注意钩子函数的返回值(如果有要求)
某些钩子函数需要返回特定的值,这些返回值可能会影响 Pytest 的后续行为。例如,pytest_runtest_makereport钩子函数需要返回修改后的测试结果报告对象,以确保正确的结果记录和处理。在编写钩子函数时,要仔细阅读 Pytest 文档,了解钩子函数的返回值要求,并确保正确返回相应的值。


3.4 注册钩子函数

编写完钩子函数代码后,需要将其注册到 Pytest 框架中,以便在测试执行过程中被正确调用。Pytest 提供了两种主要的注册钩子函数的方式:

3.4.1 使用pytest.hookimpl装饰器(推荐方式)
在定义钩子函数时,可以使用@pytest.hookimpl装饰器将其标记为一个钩子函数实现。例如:

@pytest.hookimpl(hookwrapper=True)


def pytest_runtest_makereport(item, call):
    # 钩子函数代码逻辑

使用这种方式注册钩子函数时,可以通过装饰器的参数来指定一些额外的选项,如hookwrapper=True表示将钩子函数包装为一个钩子函数包装器,允许在钩子函数执行前后执行额外的代码逻辑。

3.4.2 在conftest.py文件中直接注册
另一种方式是在conftest.py文件中直接调用config.pluginmanager.register方法来注册钩子函数。例如:

def my_hook_function(item, call):


    # 钩子函数代码逻辑


def pytest_configure(config):
    config.pluginmanager.register(my_hook_function, "my_hook_name")

这种方式相对较为繁琐,并且不太直观,因此推荐使用pytest.hookimpl装饰器来注册钩子函数。

3.5 测试与调试

完成钩子函数的编写和注册后,需要对其进行全面的测试和调试,以确保其功能正确且稳定。可以编写一些针对性的测试用例来验证钩子函数在不同情况下的行为是否符合预期。在测试过程中,可能会遇到各种问题,如钩子函数未被正确调用、逻辑错误导致测试失败或异常等。此时,需要利用 Python 的调试工具(如pdb模块)来逐步排查问题,检查钩子函数的参数值、执行流程以及与其他 Pytest 组件的交互情况,直到找到并解决问题为止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hdfs命令(三)- hdfs 管理命令(三)- hdfs dfsadmin命令

文章目录 前言一、hdfs分布式文件系统管理命令1. 介绍2. 语法及解释3. 命令3.1 生成HDFS集群的状态报告3.1.1 语法及解释3.1.2 示例 3.2 重新加载配置文件并更新NameNode中的节点列表3.3 刷新指定DataNode上的NameNode信息3.3.1 语法 3.4 获取并显示指定DataNode的信息3.4.1 语…

Word论文交叉引用一键上标

Word论文交叉引用一键上标 1.进入Microsoft word使用CtrlH快捷键或单击替换按钮 2.在查找内容中输入[^#] 3.鼠标点击,标签为“替换为:”的文本框,注意光标一定要打在图红色方框圈中的文本框中! 4.点击格式选择字体 5.勾选上标…

JAVA:最简单多线程方法调用

以下介绍在JAVA中,最简单调用多线程的方法。 在需要使用多线程方法的类中,新增线程类Thread并实现方法run。 //定义多线程class ThreadLinePoints extends Thread{private String m;public ThreadLinePoints(){}public ThreadLinePoints(String m){this…

Hadoop中MapReduce过程中Shuffle过程实现自定义排序

文章目录 Hadoop中MapReduce过程中Shuffle过程实现自定义排序一、引言二、实现WritableComparable接口1、自定义Key类 三、使用Job.setSortComparatorClass方法2、设置自定义排序器3、自定义排序器类 四、使用示例五、总结 Hadoop中MapReduce过程中Shuffle过程实现自定义排序 一…

科技云报到:人工智能时代“三大件”:生成式AI、数据、云服务

科技云报到原创。 就像自行车、手表和缝纫机是工业时代的“三大件”。生成式AI、数据、云服务正在成为智能时代的“新三大件”。加之全球人工智能新基建加速建设,成为了人类社会数字化迁徙的助推剂,让新三大件之间的耦合越来越紧密。从物理世界到数字世…

Windows 11 中部署 Linux 项目

一、总体思路 在 Windows 11 中部署 Linux 项目,主要是借助 Windows Subsystem for Linux(WSL)来实现。在WSL中新建基于Linux的项目虚拟环境,以供WIN下已克隆的项目使用。WSL 允许在 Windows 系统上运行原生的 Linux 二进制可执行…

【ETCD】【实操篇(十五)】etcd集群成员管理:如何高效地添加、删除与更新节点

etcd 是一个高可用的分布式键值存储,广泛应用于存储服务发现、配置管理等场景。为了确保集群的稳定性和可扩展性,管理成员节点的添加、删除和更新变得尤为重要。本文将指导您如何在etcd集群中处理成员管理,帮助您高效地维护集群节点。 目录 …

数据结构与算法Python版 平衡二叉查找树AVL

文章目录 一、平衡二叉查找树二、AVL树测试三、AVL树-算法分析 一、平衡二叉查找树 平衡二叉查找树-AVL树的定义 AVL树:在key插入时一直保持平衡的二叉查找树。可以利用AVL树实现抽象数据类型映射Map。与二叉查找树相比,AVL树基本上与二叉查找树的实现…

【Redis】Redis 安装与启动

在实际工作中,大多数企业选择基于 Linux 服务器来部署项目。本文演示如何使用 MobaXterm 远程连接工具,在 CentOS 7 上安装和启动 Redis 服务(三种启动方式,包括默认启动、指定配置启动和开机自启)。在安装之前&#x…

通过Js动态控制Bootstrap模态框-弹窗效果

目的&#xff1a;实现弹出窗、仅关闭弹窗之后才能操作&#xff08;按ESC可退出&#xff09;。自适应宽度与高度、当文本内容太多时、添加滚动条效果。 效果图 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…

el-table合并单元行后的多选框选中问题

问题描述 合并单元行以后&#xff0c;首列的多选框也会合并&#xff0c;此时选中该多选框其实是只选中了合并单元行的第一行的多选框&#xff0c;其他的都未被选中。 解决方案 原本想着手动去修改表头的半选状态和全选状态 &#xff0c;但是没有找到相关方法&#xff0c;后面觉…

电脑缺失libcurl.dll怎么解决?详解电脑libcurl.dll文件丢失问题

一、libcurl.dll文件丢失的原因 libcurl.dll是一个用于处理URL传输的库文件&#xff0c;广泛应用于各种基于网络的应用程序。当这个文件丢失时&#xff0c;可能会导致相关应用程序无法正常运行。以下是libcurl.dll文件丢失的一些常见原因&#xff1a; 软件安装或卸载不完整&a…

图文教程:使用PowerDesigner导出数据库表结构为Word/Html文档

1、第一种情况-无数据库表&#xff0c;但有数据模型 1.1 使用PowerDesigner已完成数据建模 您已经使用PowerDesigner完成数据库建模&#xff0c;如下图&#xff1a; 1.2 Report配置和导出 1、点击&#xff1a;Report->Reports&#xff0c;如下图&#xff1a; 2、点击&…

UE--如何用 Python 调用 C++ 及蓝图函数

前言 先讲下如何用 Python 调用 C 函数吧。 详细可见我的上篇文章 最关键的一点就是得在函数上加一个宏&#xff1a;UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable) static bool GetOrCreatePackage(const FString& PackagePath, UPackage*& OutPackag…

小程序租赁系统开发的优势与实践探索

内容概要 小程序租赁系统开发正在引起广泛关注&#xff0c;特别是在数字化快速发展的今天。很多企业开始意识到&#xff0c;小程序不仅能为他们带来更多的客户&#xff0c;还能极大地提高管理效率。借助小程序&#xff0c;用户在租赁时可以更加方便地浏览和选择产品&#xff0…

闲谭Scala(3)--使用IDEA开发Scala

1. 背景 广阔天地、大有作为的青年&#xff0c;怎么可能仅仅满足于命令行。 高端大气集成开发环境IDEA必须顶上&#xff0c;提高学习、工作效率。 开整。 2. 步骤 2.1 创建工程 打开IDEA&#xff0c;依次File-New-Project…&#xff0c;不好意思我的是中文版&#xff1a;…

富芮坤FR800X系列之PWM输出程序应用设计

文章目录 前言1.设计背景2.简介3.如何设计控制调光的接口呢4.硬件设计5.软件设计5.1.软件流程图5.2.软件代码 6.小结 前言 版权归作者所有、未经允许、请勿转载。 读者对象&#xff1a; 本文档主要适用以下工程师&#xff1a; 嵌入式系统工程师 单片机软件工程师 IOT固…

node-js Express防盗链

什么是防盗连 一个简单的说明&#xff0c;假如在前端img标签想要引用图片网站上的图片&#xff0c;当你将图片地址放到img标签上想要显示的时候你发现&#xff0c;图片显示不了&#xff0c;这说明网站采用了防盗链。 怎么实现的呢 在请求头中一般会有 Referer&#xff0c;它…

使用ArcGIS/ArcGIS pro绘制六边形/三角形/菱形渔网图

在做一些尺度分析时&#xff0c;经常会涉及到对研究区构建不同尺度的渔网进行分析&#xff0c;渔网的形状通常为规则四边形。构建渔网的方法也很简单&#xff0c;使用ArcGIS/ArcGIS Pro工具箱中的【创建渔网/CreateFishnet】工具来构建。但如果想构建其他形状渔网进行相关分析&…

RabbitMQ工作模式(详解 工作模式:简单队列、工作队列、公平分发以及消息应答和消息持久化)

文章目录 十.RabbitMQ10.1 简单队列实现10.2 Work 模式&#xff08;工作队列&#xff09;10.3 公平分发10.4 RabbitMQ 消息应答与消息持久化消息应答概念配置 消息持久化概念配置 十.RabbitMQ 10.1 简单队列实现 简单队列通常指的是一个基本的消息队列&#xff0c;它可以用于…