Pytest骨灰级教学(四)hook函数
一、简介
我们知道,pytest的自带功能已经很强大了,我们可以通过各种灵活的命令行或者配置等来灵活的实现自己想要的自动化测试效果。事实上,我们还可以通过添加插件(plugin)来扩展功能。pytest的代码结构是很适合定制和扩展插件的,而定制插件,则一定绕不开钩子函数,也就是hook函数。
1、pytest plugin加载的几种方式
a、内置plugins:从代码内部的_pytest目录加载
b、外部插件(第三方插件):通过setuptools entry points机制发现的第三方插件模块
c、conftest.py形式的本地插件:测试目录下的自动模块发现机制
通过pytest --trace-config命令可以查看当前pytest中所有的plugin。
在pytest中,所谓的plugin其实就是能被pytest发现的一些带有pytest hook方法的文件或对象。
2、什么是pytest中的hook
要理解pytest hook,首先得知道什么是hook函数(钩子函数)。hook并不是pytest独有的概念,而是在所有编程语言和系统中的非常宽泛的概念。
专业名词解释:Hook 函数又叫做钩子函数,在系统没有调用该函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。简单来说,就是把系统的程序拉出来变成我们自己执行代码片段。
简而言之,你可以理解成钩子函数是用来钩住自己喜欢的东西(在window中,喜欢的东西可理解为消息),然后对自己喜欢的东西单独做处理。
对于pytest中的hook,是为了让用户更好的去扩展开发预留的一些函数。而预留的这些函数,在整个测试执行的生命周期中特定的阶段会自动去调用执行。通过这些钩子我们可以对pytest 用例收集、用例执行、报告输出等各个阶段进行干预,根据需求去开发对应的插件,以满足自己的使用场景。
pytest中的hook函数按功能一共分为6类:引导钩子,初始化钩子、用例收集钩子、用例执行钩子、报告钩子、调试钩子。
二、引导钩子
引导钩子调用足够早,主要作用是用来解析命令和注册插件(内部插件和 setuptools 插件)。
1、pytest_load_initial_conftests
参数:
early_config:pytest配置对象(pytestconfig)。
args:命令行上传递的参数。
parser:命令行添加的选项。
触发时机:
当在命令行通过pytest执行命令时,会先执行该钩子函数
默认作用:
加载conftest.py文件
注意点:
该钩子函数只有定义在插件中才会调用,在conftest定义则不会调用
2、pytest_cmdline_main
参数:
config:pytest配置对象
触发时机:
执行运行主命令后执行
默认作用:
调用命令解析钩子pytest_cmdline_parse和执行runtest_mainloop
3、pytest_cmdline_parse
参数:
args:命令行上传递的参数。
pluginmanager :插件管理器
默认作用:
用来初始化配置对象,解析指定的参数
注意点:
该钩子函数只有定义在插件中才会调用,在conftest定义则不会调用
三、初始化钩子
初始化钩子用来调用插件和conftest.py文件的初始化
1、pytest_addoption
参数
parser :参数解析器
pluginmanager :插件管理器
触发时机:
conftest文件加载完之后执行, 在测试运行开始时调用一次。
作用:
添加运行命令的命令行参数,pytest.ini的配置参数
实例1:
# 添加一个运行参数:--qaname
def pytest_addoption(parser):
"""
1.name:自定义命令行参数的名字,可以是:“foo”, “-foo” 或 “–-foo”;
2.action:在命令行中遇到此参数时要采取的基本操作类型;
3.nargs:应该使用的命令行参数的数量;
4.const:某些操作和nargs选择所需的常量值;
5.default:如果参数不在命令行中,则生成的默认值。
6.type:命令行参数应该转换为的类型;
7.choices:参数允许值的容器;
8.required:命令行选项是否可以省略(仅可选);
9.help:对参数作用的简要说明;
10.metavar:用法消息中参数的名称;
11.dest:要添加到 parse_args() 返回的对象中的属性的名称;
"""
parser.addoption(
"--qaname",
action="store",
dest="qaname",
default="QA",
help='测试人员的名字'
)
实例2:
# 添加一个ini文件的配置项
def pytest_addoption(parser):
parser.addini(
"name",
help='参数的帮助提示信息',
type="string",
default="qa",
)
2、pytest_configure
参数
config:pytest配置对象
触发时机:
在解析命令行选项后,每个插件和初始 conftest 文件都会调用此钩子,
在导入其他 conftest 文件时调用该钩子。
默认作用:
允许插件和 conftest 文件执行初始配置。
3、pytest_unconfigure
参数
config:pytest配置对象
触发时机:
在退出测试过程之前调用
4、pytest_sessionstart
参数
session:pytest 会话对象
触发时机:
在创建Session对象之后、执行收集测试用例之前调用
5、pytest_sessionfinish
参数
session: pytest 会话对象
exitstatus: pytest 将返回系统的状态
触发时机:
在整个测试运行完成后调用,就在将退出状态返回给系统之前
6、pytest_plugin_registered
参数
plugin : 插件模块或实例
manager : pytest 插件管理器
作用:
注册一个新的插件
7、pytest_addhooks
参数
pluginmanager :插件管理器
触发时机:
注册插件时调用,添加钩子函数到执行列表
默认作用:
调用 pluginmanager.add_hookspecs(module_or_class, prefix) 注册插件
四、用例收集钩子
用例收集钩子,顾名思义就是pytest在用例收集阶段会执行的钩子函数。
1、pytest_collection
设置pytest收集用例执行的流程,这个钩子函数一般不需要重写,除非你想自己制定pytest用例收集的流程。
参数
session:pytest 会话对象
触发时机:
收集用例之前执行,执行该钩子进行用例收集
pytest默认的用例收集流程为
1、以 session作为初始收集器 ,按照下面的流程,收集所有测试用例
执行pytest_collectstart(collector)开始收集
执行report = pytest_make_collect_report(collector),创建一个收集报告对象
收集过程中,如果出现交互异常,则执行pytest_exception_interact(collector, call, report)
对收集的节点进行判断,如果是用例执行pytest_itemcollected(item),如果是收集器则进行递归处理。
执行pytest_collectreport(report),处理收集的报告
2、对收集到的用例进行修改。
执行pytest_collection_modifyitems(session, config, items)
3、整理收集到的测试用例。
执行pytest_collection_finish(session)
4、将收集的用例保存到session.items中。
5、将收集的用例数量设置为 session.testscollected 属性。
2、pytest_ignore_collect
参数
collection_path: 路径
config: pytest配置对象
触发时机:
对文件和目录进行收集之前会执行改钩子函数
返回值:
布尔值(会根据返回值为True还是False来决定是否收集改路径下的用例)
3、pytest_collect_file:搜索测试文件路径的钩子函数
参数
file_path : 收集的路径
parent : 父级目录路径
触发时机:
对每个路径进行收集之前会执行改钩子函数
返回值:
布尔值(会根据返回值为True还是False来决定是否收集该路径下的用例)
4、pytest_pycollect_makemodule:收集测试模块的钩子函数,每个测试模块都会调用该钩子函数进行收集
参数
module_path : 模块路径
触发时机:
搜索测试模块触发的钩子函数
返回值:
模块
5、pytest_pycollect_makeitem:收集模块中用例的钩子函数,对模块中的用例进行收集
参数
collector: 模块对象
name: 名称
obj: 对象
触发时机:
对文件和目录进行收集之前会执行改钩子函数
返回值:
6、pytest_generate_tests根据用例参数化传入的参数数量生成测试用例,生成测试用例
参数
metafunc : 元函数
触发时机:
对用例方法进行参数化,生成用例
7、pytest_make_parametrize_id
参数化生成用例时,生成parametrize_id(默认情况下参数化生成的用例名由原用例名和parametrize_id组成),可以通过该钩子函数修改生成用例的方法名。
参数
config : pytest 配置对象
val : 参数化值
argname: pytest 生成的自动参数名称
触发时机:
对用例方法进行参数化,生成用例名称
返回参数化的id
8、pytest_markeval_namespace:收集用例时 评估 被xfail或skipif标记用例的条件,改变测试跳过的钩子:
参数
config : pytest 配置对象
触发时机:
收集的用例被xfail或skipif标记用例时触发
9、pytest_collection_modifyitems:用例收集完成后,可以通过该钩子函数修改用例的顺序,删除或以其他方式修改测试用例。
参数
session: pytest会话对象
config : pytest 配置对象
items: 测试用例列表
触发时机:
用例收集完后调用该钩子函数
10、pytest_collection_finish
参数
session: pytest会话对象
触发时机:
在收集完用例和修改收用例集之后调用
五:测试运行钩子
所有与测试运行相关的钩子都会接收一个pytest.Item对象。
1、pytest_runtestloop:收集完成后执行主运行测试循环的钩子函数。
参数
session:pytest 会话对象
触发时机:
用例收集完后执行
默认钩子实现对会话中收集的所有项目执行 runtest 协议session.items,
除非收集失败或collectonly设置了 pytest 选项。如果在任何时候pytest.exit()调用,循环将立即终止。
如果在任何点session.shouldfail或session.shouldstop设置,循环在当前项目的运行测试协议完成后终止。
2、pytest_runtest_protocol:这个钩子函数是用来执行单个用例的,对单个测试项执行
runtest 协议
参数
Item:执行的用例
nextitem: 指定的下一条执行的测试用例
pytest默认的runtest协议为如下三个阶段:
1、设置阶段:
这个阶段主要执行用例:前置夹具
call = pytest_runtest_setup(item)
report = pytest_runtest_makereport(item, call)
pytest_runtest_logreport(report)
pytest_exception_interact(call, report)
2、调用阶段
这个阶段负责执行测试用例
call = pytest_runtest_call(item)
report = pytest_runtest_makereport(item, call)
pytest_runtest_logreport(report)
pytest_exception_interact(call, report)
3、拆解阶段
这个阶段主要执行用例:后置夹具
call = pytest_runtest_teardown(item, nextitem)
report = pytest_runtest_makereport(item, call)
pytest_runtest_logreport(report)
pytest_exception_interact(call, report)
3、pytest_runtest_logstart:在单个项目运行,runtest 协议开始时调用
参数
nodeid : 完整的节点ID
location :包含如下三个值的元组(filename, lineno, testname) ,分别为文件名、行号、用例名称
4、 pytest_runtest_logfinish:在单个项目运行,runtest 协议结束时调用
nodeid : 完整的节点ID
location :包含如下三个值的元组(filename, lineno, testname) ,分别为文件名、行号、用例名称
5、pytest_runtest_setup:在运行runTest协议时,设置阶段执行的钩子函数。该钩子函数默认实现的行为是负责执行前置的测试夹具,以及获取前置夹具中yeild返回的数据。
参数
Item:执行的用例
6、pytest_runtest_call:在运行runTest协议时,调用阶段执行的钩子函数,该钩子函数的默认实现的行为是执行:item.runtest()
参数
Item:执行的用例
7、pytest_runtest_teardown:在运行runTest协议时,拆卸阶段 执行的钩子函数。该钩子函数默认实现的行为是负责执行后置的测试夹具。
参数
Item:执行的用例
nextitem: 执行的下一条用例。
8、pytest_runtest_makereport:该钩子函数,在用例执行,runTest协议的过程中,每个阶段都会调用一次。其作用是为了创建测试执行记录器,记录每个阶段执行的结果。
参数
Item:执行的用例
call: 用例执行的阶段。
为了更深入地理解,您可以查看这些钩子的默认实现,也可以查看_pytest.runner
其中_pytest.pdb的交互_pytest.capture 及其输入/输出捕获,以便在发生测试失败时立即进入交互式调试。
9、pytest_pyfunc_call:该钩子函数的作用是为了调用底层的测试执行函数。
参数
pyfuncitem: 最终执行的用例函数

浙公网安备 33010602011771号