前言
pytest
是一个功能强大的自动化测试框架,它提供了丰富的命令行选项和配置,能够满足多种测试需求。不仅如此,
pytest
还可以通过插件机制进一步扩展了其功能。插件的定制和开发都离不开钩子函数(hook functions),因为它们是
pytest
框架中实现扩展的关键。通过钩子函数,我们可以轻松地定制和扩展
pytest的
行为,以满足更具体、更复杂的测试场景。
钩子函数的简介
想象一下我们正在参加一个晚会,而
pytest
就是这个晚会的组织者。在晚会的不同阶段,如入场、就餐、表演、离场等,都有一些固定的活动和流程。
但是,
pytest(组织者)
也想给参与者提供一些展示自我
的机会,比如允许我们在特定的时间点播放自己准备的音乐、进行特别的表演等。这些特定的时间点,在pytest中,就是所谓的“钩子”。
它们是晚会流程中预定的位置,组织者知道在这个时间点会有活动发生,但具体的活动内容是可以自定义的,而“钩子函数”,就是参与者为这些钩子提供的具体活动内容。
简而言之:
在
pytest
框架中,钩子函数(Hook Functions)
是一种特殊的函数,它们允许我们在pytest
的内部处理流程中特定的点插入自定义的行为。这些特定的点被称为
“钩子”(Hooks)
,它们定义在pytest
的内部,而我们可以通过实现相应的钩子函数来定制pytest
的行为。
钩子函数的作用
- 扩展功能:钩子函数允许我们扩展
pytest
的功能,添加额外的行为或修改默认的行为。- 定制流程:可以通过钩子函数在测试执行的不同阶段定制流程,例如测试准备、测试执行、测试结果处理等。
- 集成第三方工具:钩子函数可以用于集成第三方工具或库,与
pytest
的测试流程相结合,提供更丰富的功能和更灵活的处理方式。
钩子函数的加载
- 内置插件:
pytest
自带了一些内置插件,这些插件为pytest
提供了核心功能。它们通常位于_pytest
目录中,这是pytest
的内部包,包含了框架的核心实现和插件- 第三方插件:可以通过
setuptools
的entry_points
机制来注册和发现。当你在setup.py
文件中为你的插件定义了一个pytest
入口点时,pytest
就能够在运行时发现并加载它。- 本地插件:
conftest.py
文件是一种特殊的本地插件,pytest
会在其目录树中自动发现并加载它们。这些文件可以包含pytest
的钩子函数、fixture
和其他配置。
钩子函数的分类
pytest
有非常多的插件,居pypi
统计目前已高达1400+
官网地址:https://docs.pytest.org/en/latest/reference/plugin_list.html#plugin-list
如果我们按照测试执行的流程来划分钩子的位置,可以大致分为以下几个阶段(不完全统计):
初始化与配置阶段
pytest_cmdline_main
: 当从命令行运行pytest时被调用,是pytest的主入口点。
pytest_configure
: pytest配置阶段调用,用于设置测试环境。
pytest_plugin_registered
: 当pytest插件注册时调用。
pytest_report_header
: 用于生成测试报告时的自定义标题。
pytest_addoption
:用于向pytest的命令行解析器添加自定义选项。
pytest_sessionstart
: 整个测试会话开始时调用。用例收集阶段
pytest_collect_file
: 收集单个文件作为测试模块时调用。pytest_collect_directory
: 收集目录作为测试模块时调用。pytest_collect_module
: 收集Python模块作为测试模块时调用。pytest_collect_item
: 收集单个测试项(如函数、方法或类)时调用。pytest_generate_tests
: 生成测试用例时调用,常用于参数化。pytest_make_parametrize_id
: 为参数化测试生成ID时调用。pytest_collection_modifyitems
: 修改已收集的测试用例项时调用。pytest_collection_finish
: 用例收集阶段结束时调用。用例准备与执行阶段
pytest_runtest_protocol
: 开始执行单个测试项之前调用,用于设置执行协议。pytest_runtest_setup
: 在执行测试项之前设置fixture和其他准备工作时调用。pytest_runtest_call
: 实际执行测试项(如函数或方法)时调用。pytest_runtest_teardown
: 在测试项执行完毕后进行清理时调用。pytest_runtest_logstart
: 用于开始测试项的日志记录。pytest_runtest_logfinish
: 用于结束测试项的日志记录。报告与总结阶段
pytest_make_collect_report
: 生成收集阶段的测试报告。pytest_collectreport
: 生成收集阶段的测试报告。pytest_make_test_report
: 生成测试项的执行报告.pytest_runtest_makereport
: 生成测试项的执行报告。pytest_report_teststatus
: 报告单个测试项的状态时调用。pytest_terminal_summary
: 在终端显示测试总结信息时调用。pytest_sessionfinish
: 整个测试会话结束时调用。异常与调试阶段
pytest_exception_interact
: 当未捕获的异常导致测试失败时,允许用户交互地调试。pytest_internalerror
: 当pytest遇到内部错误时调用。清理与卸载阶段
pytest_unconfigure
: 在pytest配置清理阶段调用,用于清理测试环境。
第一个钩子函数-失败重跑
- 作用说明:
pytest
失败重跑插件可以在测试用例执行失败后进行重新执行,以提高测试的可靠性和稳定性。- 应用场景:当服务器不稳定、网络波动等导致用例执行失败时,可以使用该插件进行失败重跑,以避免因偶然因素导致的测试失败。
- 使用规则:需要安装
pytest-rerunfailures
插件,并在pytest
命令行中添加相应的参数来指定重跑的次数和延时时间等。
插件安装
安装命令:
pip install pytest-rerunfailures
使用方式一:命令行
作用域:全局
命令行参数:
--reruns n
:这个参数用于指定一个测试用例失败后最多重跑的次数。n
是一个正整数,表示重跑的次数。这是一个必填参数。--reruns-delay m
:这个参数用于指定两次重跑之间的延迟时间(以秒为单位)。m
是一个正整数,表示延迟的秒数。这是一个可选参数。- 命令示例:
pytest --reruns 3 --reruns-delay 1
示例代码
def test_case_01():
assert 1 == 1, "断言失败"
def test_case_02():
assert 1 == 2, "断言失败"
执行结果
使用方式二:配置文件
作用域:全局
功能描述:可以在
pytest.ini
配置文件中设置这些参数,这样就不需要在每次运行测试时都指定它们了。注意说明:
addopts
配置项中的-vs
是额外的选项,用于启用详细输出(-v
表示详细输出,s
表示显示捕获的输出)。这些并不是
pytest-rerunfailures
插件必需的,而是用于演示如何在addopts
中添加多个选项。
pytest.ini
配置文件添加如下
[pytest]
addopts = -vs --reruns=2 --reruns-delay=1
示例代码
def test_case_01():
assert 1 == 1, "断言失败"
def test_case_02():
assert 1 == 2, "断言失败"
执行结果
使用方式三:装饰器
作用域:局部
功能描述:@pytest.mark.flaky(reruns=m, reruns_delay=n)
是一个pytest的装饰器,用于标记那些可能会偶尔失败但通常能够成功通过的测试用例。当使用此装饰器时,如果标记的测试用例失败,pytest会尝试重新运行该用例指定的次数。参数含义:
reruns=m
:指定如果测试用例失败,应重新运行的次数。m
是一个整数,表示重跑的次数。reruns_delay=n
:指定每次重跑之间的延迟时间(以秒为单位)。n
是一个整数,表示每次重跑前等待的秒数。
示例代码
import pytest
def test_case_01():
assert 1 == 1, "断言失败"
@pytest.mark.flaky(reruns=3, reruns_delay=1)
def test_case_02():
assert 1 == 2, "断言失败"
执行结果