前言
pytest运行的整个过程中, 充满了各种Hook函数
覆写Hook函数虽然无法改变pytest的执行流程, 但可以实现用户自定义行为
比如collection阶段, 可以不局限于test开头的模块和方法; run阶段, 可以过滤特殊的方法
官网中描述了以下几种hook函数
- Bootstrapping hooks, 启动pytest时引入
- Initialization hooks, 初始化插件, 及conftest.py文件
- Test running hooks, 执行case时调用
- Collection hooks, 从目录/文件中发现testcase
- Reporting hooks, 报告相关
- Debugging/Interaction hooks, 特殊hook函数, 异常交互相关
实例
解析yml文件, 从中提取接口参数, 并执行接口测试
conftest.py文件
import pytest
import sys
import requests
def pytest_collect_file(path, parent):
"""
定义yml后缀, 且以unit开头的文件, 将被诹
:param path: 文件全路径
:param parent: session
:return: collector
"""
if path.ext == ".yml" and path.basename.startswith("unit"):
return YamlFile(path, parent)
class YamlFile(pytest.File):
def collect(self):
'''
collector调用collect方法, 会从文件中提取Item对象, 即testcase
:return: [Items]
'''
import yaml
raw = yaml.safe_load(self.fspath.open())
for name, attrs in raw.items():
yield YamlItem(name, self, attrs)
class YamlItem(pytest.Item):
def __init__(self, name, parent, attrs):
super(YamlItem, self).__init__(name, parent)
self.attrs = attrs
def setup(self):
'''
Item 对象的初始化步骤, 同样还有teardown方法, 这里省略
:return:
'''
if 'setup' in self.attrs:
for action, args in self.attrs['setup'].items():
getattr(sys.modules['builtins'], action)(args)
def runtest(self):
'''
执行Item对象时, 会调用runtest方法
所以这里定义具体的测试行为
:return:
'''
try:
url = self.attrs['body']['url']
data = self.attrs['body']['data']
expected = self.attrs['expected']
resp = requests.get(url, params=data)
actual = resp.json()
for key, value in expected.items():
assert actual['args'][key] == value
except KeyError:
raise YamlException(self.name)
class YamlException(Exception):
pass
unit_get.yml文件
my_get_request:
body:
url: https://httpbin.org/get
data:
keyword: cucumber
setup:
print: setup step
expected:
keyword: cucumber
执行pytest
即可查看运行结果
相关类介绍
_pytest.config.Parser
解析命令行参数, 以及ini文件, 将结果传递给Config
addoption(self, *opts, **attrs)
group.addoption(
"--maxfail",
metavar="num",
action="store",
type=int,
dest="maxfail",
default=0,
help="exit after first num failures or errors.",
)
addini(self, name, help, type=None, default=None)
parser.addini(
"python_files",
type="args",
default=["test_*.py", "*_test.py"],
help="glob-style file patterns for Python test module discovery",
)
_pytest.config.Config
记录命令行的参数option, 以及ini属性
getoption(self, name, default=notset, skip=False)
getini(self, name)
_pytest.main.Session
包含config, testsfailed, testscollected等属性
pytest.Item
即testcase, 继承自Node, 基本属性如下
def __init__(
self, name, parent=None, config=None, session=None, fspath=None, nodeid=None
):
#: a unique name within the scope of the parent node
self.name = name
#: the parent collector node.
self.parent = parent
#: the pytest config object
self.config = config or parent.config
#: the session this node is part of
self.session = session or parent.session
#: filesystem path where this node was collected from (can be None)
self.fspath = fspath or getattr(parent, "fspath", None)
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
#: the marker objects belonging to this node
self.own_markers = []
#: allow adding of extra keywords to use for matching
self.extra_keyword_matches = set()
# used for storing artificial fixturedefs for direct parametrization
self._name2pseudofixturedef = {}
Initialization hooks
pytest_addoption(parser)
通过Parser注册命令行参数, 以及添加ini-stype属性
pytest_configure(config)
命令行解析完成后, 初始化conftest.py文件时执行
def pytest_addoption(parser):
parser.addoption(
"--season",
dest="seasion",
default="summer",
)
def pytest_configure(config):
print("season ==> {}".format(config.getoption("seasion")))
===============================
season ==> summer
pytest_unconfigure(config)
测试进程结束前执行
pytest_sessionstart(session)
会话创建时, 尚未收集testcase, 比configure阶段晚
pytest_sessionfinish(session, exitstatus)
整个测试完成后执行
Test running hooks
所有的testcase都被封装成pytest.Item对象
pytest_runtestloop(session)
collection阶段完成后, 启动测试任务时调用
pytest_runtest_logstart(nodeid, location)/pytest_runtest_logfinish(nodeid, location)
执行单条用例, 比pytest_runtest_setup()早
location = (filename, linenum, testname)
pytest_runtest_setup(item)
pytest_runtest_call(item)
pytest_runtest_teardown(item, nextitem)
Collection hooks
pytest采取一定规则, 去特定目录和文件中检索testcase, 而Collection hooks可以定义这些规则
pytest_collection(session)
执行collection操作
pytest_ignore_collect(path, config)
如果返回True, 则忽略掉path路径, 优先执行
pytest_collect_directory(path, parent)
开始扫描目录, 如何处理目录下的文件, 及子目录
pytest_collect_file(path, parent)
汇总测试文件, 作为collection Node, 用于后续提取testcase
pytest_pycollect_makeitem(collector, name, obj)
从已收集的文件中提取出用例, 并封装成item
pytest_generate_tests(metafunc)
向测试方法传递参数, 形成多次调用效果
pytest_collection_modifyitems(session, config, items)
所有的测试用例收集完毕后调用, 可以再次过滤或者对它们重新排序