Arbeiten mit Nicht-Python-Tests

Ein einfaches Beispiel für die Spezifikation von Tests in Yaml-Dateien

Hier ist ein Beispiel für eine conftest.py (entnommen aus Ali Afshars speziellem Plugin pytest-yamlwsgi). Dieses conftest.py sammelt test*.yaml-Dateien und führt den YAML-formatierten Inhalt als benutzerdefinierte Tests aus.

# content of conftest.py
from __future__ import annotations

import pytest


def pytest_collect_file(parent, file_path):
    if file_path.suffix == ".yaml" and file_path.name.startswith("test"):
        return YamlFile.from_parent(parent, path=file_path)


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

        raw = yaml.safe_load(self.path.open(encoding="utf-8"))
        for name, spec in sorted(raw.items()):
            yield YamlItem.from_parent(self, name=name, spec=spec)


class YamlItem(pytest.Item):
    def __init__(self, *, spec, **kwargs):
        super().__init__(**kwargs)
        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.",
                ]
            )
        return super().repr_failure(excinfo)

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


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

Sie können eine einfache Beispieldatei erstellen.

# test_simple.yaml
ok:
    sub1: sub1

hello:
    world: world
    some: other

Und wenn Sie PyYAML oder einen kompatiblen YAML-Parser installiert haben, können Sie nun die Testspezifikation ausführen.

nonpython $ pytest test_simple.yaml
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project/nonpython
collected 2 items

test_simple.yaml F.                                                  [100%]

================================= FAILURES =================================
______________________________ usecase: hello ______________________________
usecase execution failed
   spec failed: 'some': 'other'
   no further details known at this point.
========================= short test summary info ==========================
FAILED test_simple.yaml::hello - usecase execution failed
======================= 1 failed, 1 passed in 0.12s ========================

Sie erhalten einen Punkt für die erfolgreich bestandene Prüfung sub1: sub1 und einen Fehler. Offensichtlich werden Sie in der obigen conftest.py eine interessantere Interpretation der YAML-Werte implementieren wollen. Sie können auf diese Weise leicht Ihre eigene domänenspezifische Testsprache schreiben.

Hinweis

repr_failure(excinfo) wird zum Darstellen von Testfehlern aufgerufen. Wenn Sie benutzerdefinierte Sammelknoten erstellen, können Sie eine Fehlersymbolzeichenkette Ihrer Wahl zurückgeben. Sie wird als (rote) Zeichenkette gemeldet.

reportinfo() wird zum Darstellen des Testorts verwendet und wird auch bei der Berichterstattung im verbose-Modus konsultiert.

nonpython $ pytest -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: /home/sweet/project/nonpython
collecting ... collected 2 items

test_simple.yaml::hello FAILED                                       [ 50%]
test_simple.yaml::ok PASSED                                          [100%]

================================= FAILURES =================================
______________________________ usecase: hello ______________________________
usecase execution failed
   spec failed: 'some': 'other'
   no further details known at this point.
========================= short test summary info ==========================
FAILED test_simple.yaml::hello - usecase execution failed
======================= 1 failed, 1 passed in 0.12s ========================

Während der Entwicklung Ihrer benutzerdefinierten Testsammlung und -ausführung ist es auch interessant, einfach den Sammlungbaum zu betrachten.

nonpython $ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project/nonpython
collected 2 items

<Package nonpython>
  <YamlFile test_simple.yaml>
    <YamlItem hello>
    <YamlItem ok>

======================== 2 tests collected in 0.12s ========================