• pytest文档83 - 把收集的 yaml 文件转 Item 用例并运行


    前言

    上一篇通过用例收集钩子 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    先在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)
    
    • 1
    • 2
    • 3
    • 4

    如果收集到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 
        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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    报错位置在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")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    由于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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    再次运行pytest

    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    item = 
    
        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 = 
    
        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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这次出现的报错在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")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来就需要重写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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    输入pytest就可以看到yaml文件被当成用例去执行了

  • 相关阅读:
    [c++基础]-vector类
    反转链表算法
    【Mycat1.6】缓存不生效问题处理
    Word控件Spire.Doc 【页面背景】教程(9) ;C#/VB.NET:从 Word 文档中删除文本或图像水印
    设计模式-代理模式
    【数据聚类】第三章第三节4:类K-Means算法之二分K-均值算法(bisecting K-Means算法)
    【Arduino+ESP32专题】案例:串口接收字符串并按指定分隔符分割
    Linux下安装配置各种软件和服务
    基于TCP的简易电子词典
    12 Synchronized与锁升级
  • 原文地址:https://blog.csdn.net/qq_27371025/article/details/128118808