pytest测试框架-内置插件Hook函数
Hook函数:钩子函数,比如人照镜子,镜子里的自己是虚拟的,是一个影子,影子是不能做任何操作的,自己动的时候影子才会动,在程序中影子相当于hook,ta本身没有实现步骤,自己代表实现。
- 是个函数,在系统消息触发时被系统调用;
- 自动触发机制;
- Hook函数的名称是确定的;
- pytest有非常多的钩子函数;
- 使用时直接编写函数体;
pytest测试用例的执行顺序:
- pytest_addoption:添加命令行参数,运行时先读取命令行参数
- pytest_collection_modifyitems:收集测试用例,收集之后改编码,改执行顺序
- pytest_collection_finish:收集之后的操作
- pytest_runtest_setup:在调用pytest_runtest_call之前调用
- pytest_runtest_call:调用执行测试的用例
- pytest_runtest_makereport:运行测试用例,返回setup,call,teardown的执行结果
pytest hook的执行顺序
root
└── pytest_cmdline_main
├── pytest_plugin_registered
├── pytest_configure
│ └── pytest_plugin_registered
├── pytest_sessionstart
│ ├── pytest_plugin_registered
│ └── pytest_report_header
├── pytest_collection
│ ├── pytest_collectstart
│ ├── pytest_make_collect_report
│ │ ├── pytest_collect_file
│ │ │ └── pytest_pycollect_makemodule
│ │ └── pytest_pycollect_makeitem
│ │ └── pytest_generate_tests
│ │ └── pytest_make_parametrize_id
│ ├── pytest_collectreport
│ ├── pytest_itemcollected
│ ├── pytest_collection_modifyitems
│ └── pytest_collection_finish
│ └── pytest_report_collectionfinish
├── pytest_runtestloop
│ └── pytest_runtest_protocol
│ ├── pytest_runtest_logstart
│ ├── pytest_runtest_setup
│ │ └── pytest_fixture_setup
│ ├── pytest_runtest_makereport
│ ├── pytest_runtest_logreport
│ │ └── pytest_report_teststatus
│ ├── pytest_runtest_call
│ │ └── pytest_pyfunc_call
│ ├── pytest_runtest_teardown
│ │ └── pytest_fixture_post_finalizer
│ └── pytest_runtest_logfinish
├── pytest_sessionfinish
│ └── pytest_terminal_summary
└── pytest_unconfigure
Hook函数的使用
示例:先在conftest.py文件中加上hook的配置,然后写一个测试用例,执行,用例的执行顺序按hook配置执行~
conftest.py的配置:
from typing import Optional
def pytest_runtest_setup(item: "Item") -> None:
print("hook:setup")
def pytest_runtest_teardown(item: "Item", nextitem:Optional["Item"]) -> None:
print("teardown")
测试代码test_hook.py:
def test_case():
print("\n")
pass
执行结果:
image.png
用Hook函数写插件
-
1.修改用例名称中的默认参数编码格式
- 场景:用例中传参为中文时,格式展示问题
import pytest
@pytest.mark.parametrize('name', ["吱吱菌啦啦", "测试ziz"])
def test_case(name):
print(f"名称测试:{name}")
# name 用例的名字
# nodeid就是测试用例的路径
编写测试代码,执行;未修改编码前,用例名称的展示:
image.png
conftest.py文件中对收集测试用例进行二次开发,然后对item进行encode('utf-8').decode('unicode-escape')
# 收集完测试用例之后被调用的hook函数,对中文传参进行decode
def pytest_collection_modifyitems(session: "Session", config: "Config", items: List["Item"]) -> None:
print(items)
# 遍历item,对名称和用例路径_nodeid进行编码
for item in items:
item.name = item.name.encode('utf-8').decode('unicode-escape')
item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')
修改编码后,再次执行测试代码,用例名称的展示:
image.png
2.添加命令行参数
conftest.py文件的修改
# 定义一个命令行参数
def pytest_addoption(parser):
mygroup = parser.getgroup("hogwarts") #group 将下面所有的 option都展示在这个group下。
mygroup.addoption("--env", #注册一个命令行选项
default='test', # 参数的默认值
dest='env', # 存储的变量
help='set your run env' # 帮助提示 参数的描述信息
)
mygroup.addoption("--env1", # 注册一个命令行选项
default='test1', # 参数的默认值
dest='env1', # 存储的变量
help='set your run env' # 帮助提示 参数的描述信息
)
# 针对传入的不同参数完成不同的逻辑处理
@pytest.fixture(scope='session')
def cmdoption(request):
myenv = request.config.getoption("--env",default='test')
if myenv == 'test':
datapath = 'datas/test/data.yml'
if myenv == 'dev':
datapath = 'datas/dev/data.yml'
with open(datapath) as file:
datas = yaml.safe_load(file)
return myenv, datas
执行测试代码,会打印当前环境及读取对应yaml文件中的数据
也可以用命令行执行:
pytest test_hook_plugin_option.py --env dev -vs
pytest test_hook_plugin_option.py --env test -vs
def test_option(cmdoption):
print(cmdoption)