前言
上一篇通过用例收集钩子 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: POSTheaders:Content-Type: application/jsonjson:username: testpassword: 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_callresult: 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 collectraise 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 thusiteratively 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 thiscollection 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_typedel sys.last_valuedel sys.last_tracebackexcept AttributeError:passtry:
> 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 subclassvenv\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 Pathdef 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 = nameself.values = valuesself.s = requests.session()def runtest(self) -> None:"""运行用例"""request_data = self.values["request"]response = self.s.request(**request_data)print("\n", response.text)
输入pytest就可以看到yaml文件被当成用例去执行了