pytest+yaml+allure接口自動化測試框架03.讀取測試用例文件


前言

​ 使用yaml作為測試用例,我們就需要對文件的內容進行讀取,常規來說的應該是通過pyyaml對讀取到的內容進行數據解析,然后使用pytest parametrize參數化功能進行數據參數化用例測試。但是完事之后,這樣的方式好像不是很優雅,寫的代碼組織起來比較費勁,於是乎,我在pytest的官方文檔中,發現了一套更為一套非常優雅的測試執行方式,他們稱之為non-python test的測試模式。

具體內容可以查看官方文檔,感興趣的可以去看看:Working with non-python tests — pytest documentation

# content of conftest.py
import pytest


def pytest_collect_file(parent, path):
    if path.ext == ".yaml" and path.basename.startswith("test"):
        return YamlFile.from_parent(parent, fspath=path)


class YamlFile(pytest.File):
    def collect(self):
        # We need a yaml parser, e.g. PyYAML.
        import yaml

        raw = yaml.safe_load(self.fspath.open())
        for name, spec in sorted(raw.items()):
            yield YamlItem.from_parent(self, name=name, spec=spec)


class YamlItem(pytest.Item):
    def __init__(self, name, parent, spec):
        super().__init__(name, parent)
        self.spec = spec

    def runtest(self):
        for name, value in sorted(self.spec.items()):
            # Some custom test execution (dumb example follows).
            if name != value:
                raise YamlException(self, name, value)

    def repr_failure(self, excinfo):
        """Called when self.runtest() raises an exception."""
        if isinstance(excinfo.value, YamlException):
            return "\n".join(
                [
                    "usecase execution failed",
                    "   spec failed: {1!r}: {2!r}".format(*excinfo.value.args),
                    "   no further details known at this point.",
                ]
            )

    def reportinfo(self):
        return self.fspath, 0, f"usecase: {self.name}"


class YamlException(Exception):
    """Custom exception for error reporting."""

可以看到官方文檔中以極其優雅的方式通過yaml文件驅動了兩個測試用例。我們也將在此基礎上進行擴展衍生。

讀取yaml文件

​ 我們根據官方文檔中的示例文件,在這個基礎上進行修改,加入我們的內容。

pytest_collect_file

首先我們修改pytest_collect_file函數中的內容,讓他支持yamlyml兩種格式的文件內容。因為這兩種都可以,官網示例中只有一個。

if path.ext in (".yaml", ".yml") and path.basename.startswith("test"):
    return YamlFile.from_parent(parent, fspath=path)

YamlFile.collect

接下來修改我們的YamlFile.collect方法,這里面就是對讀出來的詳細內容按照設置的格式進行處理,該存入緩存的放入緩存,該執行測試的時候執行測試。

if not any(k.startswith('test') for k in raw.keys()):
    raise YamlException("{}yaml non test found".format(self.fspath))

通過這個語句我們先判斷一下,有沒有測試用例,如果沒有測試用例我們直接就報錯了,不在執行,拋出異常,這個異常需要我們自己封裝一下。我們打開common/exceptions.py文件。輸入以下內容:

# -*- coding: utf-8 -*-
__author__ = 'wxhou'
__email__ = '1084502012@qq.com'
"""
異常類
"""
from requests.exceptions import RequestException


class YamlException(Exception):
    """Custom exception for error reporting."""

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return "\n".join(
            [
                "usecase execution failed",
                "   spec failed: {}".format(self.value),
                "   For more details, see this the document.",
            ]
        )

這個就是當我們發現yaml文件中沒有符合的測試標簽內容后拋出的異常類。

然后我們接着先讀取全局變量:

if variable := raw.get('variable'):
    for k, v in variable.items():
        cache.set(k, v)

我們把yaml文件中預設的全局變量信息中全部存在我們設置的緩存模塊中,這樣在測試過程中我們可以隨時的去用。

繼續讀取配置文件。

if config := raw.get('config'):   
    for k, v in config.items():
        cache.set(k, v)

然后我們讀取常用的測試信息也放入緩存之中,方便運行過程中隨時去調用。

最后我們來處理一下。測試用例部分:

if tests := raw.get('tests'):
    for name, spec in tests.items():
        yield YamlTest.from_parent(self,
                                   name=spec.get('description') or name,
                                   spec=spec)

可以看到,在官方文檔中使用了sorted函數進行了再次排序。我這里沒有是因為再次排序會破壞用例的結構和順序。最后輸出的時候spec.get('description') or name的寫法先獲取yaml文件中我們設置的中文標識,如果中文標識不存在則繼續使用英文標識。其余和官方文檔保持一致。

以上就是做出的改動,我們來看看吧:

import yaml
import pytest
from common.cache import cache
from common.exceptions import YamlException


def pytest_collect_file(parent, path):
    if path.ext in (".yaml", ".yml") and path.basename.startswith("test"):
        return YamlFile.from_parent(parent, fspath=path)


class YamlFile(pytest.File):

    def collect(self):
        raw = yaml.safe_load(self.fspath.open(encoding='utf-8'))
        if not any(k.startswith('test') for k in raw.keys()):
            raise YamlException("{}yaml non test found".format(self.fspath))
        if variable := raw.get('variable'):
            for k, v in variable.items():
                cache.set(k, v)
        if config := raw.get('config'):
            for k, v in config.items():
                cache.set(k, v)
        if tests := raw.get('tests'):
            for name, spec in tests.items():
                yield YamlTest.from_parent(self,
                                           name=spec.get(
                                               'description') or name,
                                           spec=spec)

站在巨人的肩膀上才能看得更遠。在pytest non-python tests的內容之上做了一些改動,使得讀取文件更加貼合我們定義的yaml文件內容。在精簡了很多代碼的同時我們也達到了預期的效果。

至此,本章的讀取yaml測試文件到此結束。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM