前言
上一篇通过用例收集钩子 pytest_collect_file 把 yaml 文件收集起来的,仅仅只是收集到用例,还不能执行。
接下来详细讲解,如何把yaml 文件的内容,转成Item 用例去执行。
pytest_collect_file 收集钩子
准备一个待执行的YAML文件内容test_login.yml
name: login case1
request:
url: http://127.0.0.1:8000/api/v1/login/
method: POST
headers:
Content-Type: application/json
json:
username: test
password: 123456
先在conftest.py 写收集钩子
def pytest_collect_file(file_path: Path, parent):
# 获取文件.yml 文件,匹配规则
if file_path.suffix == ".yml" and file_path.name.startswith("test"):
return pytest.File.from_parent(parent, path=file_path)
如果收集到yaml 文件返回pytest.File.from_parent(parent, path=file_path)
,在运行的时候会出现报错
============================================ ERRORS ============================================
_____________________________ ERROR collecting case/test_login.yml _____________________________
venv\lib\site-packages\_pytest\runner.py:339: in from_call
result: Optional[TResult] = func()
venv\lib\site-packages\_pytest\runner.py:370: in <lambda>
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
venv\lib\site-packages\_pytest\nodes.py:536: in collect
raise NotImplementedError("abstract")
E NotImplementedError: abstract
=================================== short test summary info ====================================
ERROR case/test_login.yml - NotImplementedError: abstract
!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!
报错位置在nodes.py文件里面的collect() 方法,于是找到nodes.py 里面的Collector
class Collector(Node):
"""Collector instances create children through collect() and thus
iteratively build a tree."""
class CollectError(Exception):
"""An error during collection, contains a custom message."""
def collect(self) -> Iterable[Union["Item", "Collector"]]:
"""Return a list of children (items and collectors) for this
collection node."""
raise NotImplementedError("abstract")
由于collect() 方法是空的,直接raise 一个异常NotImplementedError("abstract")
, 于是我们需要重写collect() 方法
YamlFile 重写collect()
对应一个YamlFile 类,继承ytest.File,重写collect()方法
- raw 是读取yaml文件的完整内容
- name=raw.get(‘name’),name参数是设置用例的名称
- values=raw,values是自定义的一个参数,读取的yaml文件测试数据
class YamlFile(pytest.File):
def collect(self):
"""返回读取内容的Iterable 可迭代对象"""
raw = yaml.safe_load(self.fspath.open(encoding='utf-8'))
print(raw)
# raw 是读取 yml 数据的内容
yield pytest.Item.from_parent(self, name=raw.get('name'), values=raw)
再次运行pytest
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
item = <Item login case1>
def pytest_runtest_call(item: Item) -> None:
_update_current_test_var(item, "call")
try:
del sys.last_type
del sys.last_value
del sys.last_traceback
except AttributeError:
pass
try:
> item.runtest()
venv\lib\site-packages\_pytest\runner.py:167:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Item login case1>
def runtest(self) -> None:
"""Run the test case for this item.
Must be implemented by subclasses.
.. seealso:: :ref:`non-python tests`
"""
> raise NotImplementedError("runtest must be implemented by Item subclass")
E NotImplementedError: runtest must be implemented by Item subclass
venv\lib\site-packages\_pytest\nodes.py:733: NotImplementedError
这次出现的报错在runner.py 文件,执行runtest() 方法抛出的异常NotImplementedError("runtest must be implemented by Item subclass")
看到这里,说明用例Item 已经生成了,在执行的时候,没有定义一个执行yaml文件的方法,所以报错了
于是找到nodes.py 里面的 Item(Node)
类
class Item(Node):
"""A basic test invocation item.
Note that for a single function there might be multiple test invocation items.
"""
def runtest(self) -> None:
"""Run the test case for this item.
Must be implemented by subclasses.
.. seealso:: :ref:`non-python tests`
"""
raise NotImplementedError("runtest must be implemented by Item subclass")
接下来就需要重写Item 里面的runtest 去执行用例
重写Item 的runtest
最终看到的一个简版执行yaml文件的接口用例conftest.py 如下
import pytest
import requests
import yaml
from pathlib import Path
def pytest_collect_file(file_path: Path, parent):
# 获取文件.yml 文件,匹配规则
if file_path.suffix == ".yml" and file_path.name.startswith("test"):
return YamlFile.from_parent(parent, path=file_path)
class YamlFile(pytest.File):
def collect(self):
"""返回读取内容的Iterable 可迭代对象"""
raw = yaml.safe_load(self.fspath.open(encoding='utf-8'))
print(raw)
# raw 是读取 yml 数据的内容
yield YamlTest.from_parent(self, name=raw.get('name'), values=raw)
class YamlTest(pytest.Item):
def __init__(self, name, parent, values):
super(YamlTest, self).__init__(name, parent)
self.name = name
self.values = values
self.s = requests.session()
def runtest(self) -> None:
"""运行用例"""
request_data = self.values["request"]
response = self.s.request(**request_data)
print("\n", response.text)
输入pytest就可以看到yaml文件被当成用例去执行了