Erste Schritte

Installieren von pytest

  1. Führen Sie den folgenden Befehl in Ihrer Kommandozeile aus

pip install -U pytest
  1. Prüfen Sie, ob Sie die richtige Version installiert haben

$ pytest --version
pytest 9.0.1

Erstellen Sie Ihren ersten Test

Erstellen Sie eine neue Datei namens test_sample.py, die eine Funktion und einen Test enthält

# content of test_sample.py
def func(x):
    return x + 1


def test_answer():
    assert func(3) == 5

Der Test

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

test_sample.py F                                                     [100%]

================================= FAILURES =================================
_______________________________ test_answer ________________________________

    def test_answer():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)

test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================

Die Angabe [100%] bezieht sich auf den Gesamtfortschritt der Ausführung aller Testfälle. Nachdem sie abgeschlossen ist, zeigt pytest einen Fehlerbericht an, da func(3) nicht 5 zurückgibt.

Hinweis

Sie können die assert-Anweisung verwenden, um Testerwartungen zu überprüfen. Pytests Erweiterte Assertions-Introspektion berichtet intelligent über Zwischenwerte des Assertionsausdrucks, sodass Sie die vielen Namen von JUnit-Legacy-Methoden vermeiden können.

Mehrere Tests ausführen

pytest führt alle Dateien mit dem Muster test_*.py oder *_test.py im aktuellen Verzeichnis und seinen Unterverzeichnissen aus. Allgemeiner folgt es den Standardregeln zur Testentdeckung.

Bestätigen, dass eine bestimmte Ausnahme ausgelöst wird

Verwenden Sie die Hilfsfunktion raises, um zu bestätigen, dass ein Code eine Ausnahme auslöst

# content of test_sysexit.py
import pytest


def f():
    raise SystemExit(1)


def test_mytest():
    with pytest.raises(SystemExit):
        f()

Führen Sie die Testfunktion im Modus "stille" Berichterstattung aus

$ pytest -q test_sysexit.py
.                                                                    [100%]
1 passed in 0.12s

Hinweis

Das Flag -q/--quiet hält die Ausgabe in diesem und den folgenden Beispielen kurz.

Weitere Details zur erwarteten Ausnahme finden Sie unter Assertions über ungefähre Gleichheit.

Mehrere Tests in einer Klasse gruppieren

Wenn Sie mehrere Tests entwickelt haben, möchten Sie diese möglicherweise in einer Klasse gruppieren. pytest erleichtert die Erstellung einer Klasse, die mehr als einen Test enthält

# content of test_class.py
class TestClass:
    def test_one(self):
        x = "this"
        assert "h" in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, "check")

pytest entdeckt alle Tests gemäß seinen Konventionen für die Python-Testentdeckung, sodass es beide Funktionen mit dem Präfix test_ findet. Es ist nicht notwendig, etwas zu unterklassen, aber stellen Sie sicher, dass Sie Ihre Klasse mit Test präfixen, da sie sonst übersprungen wird. Wir können das Modul einfach ausführen, indem wir seinen Dateinamen übergeben

$ pytest -q test_class.py
.F                                                                   [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________

self = <test_class.TestClass object at 0xdeadbeef0001>

    def test_two(self):
        x = "hello"
>       assert hasattr(x, "check")
E       AssertionError: assert False
E        +  where False = hasattr('hello', 'check')

test_class.py:8: AssertionError
========================= short test summary info ==========================
FAILED test_class.py::TestClass::test_two - AssertionError: assert False
1 failed, 1 passed in 0.12s

Der erste Test war erfolgreich und der zweite ist fehlgeschlagen. Sie können die Zwischenwerte in der Assertion leicht sehen, um den Grund für den Fehler zu verstehen.

Die Gruppierung von Tests in Klassen kann aus folgenden Gründen von Vorteil sein

  • Testorganisation

  • Freigabe von Fixtures für Tests, die nur in dieser spezifischen Klasse enthalten sind

  • Anwenden von Markierungen auf Klassenebene, sodass sie implizit auf alle Tests angewendet werden

Etwas, das Sie beachten sollten, wenn Sie Tests in Klassen gruppieren, ist, dass jeder Test eine eindeutige Instanz der Klasse hat. Wenn jeder Test dieselbe Klasseninstanz teilt, wäre dies sehr nachteilig für die Testisolation und würde schlechte Testpraktiken fördern. Dies wird im Folgenden erläutert

# content of test_class_demo.py
class TestClassDemoInstance:
    value = 0

    def test_one(self):
        self.value = 1
        assert self.value == 1

    def test_two(self):
        assert self.value == 1
$ pytest -k TestClassDemoInstance -q
.F                                                                   [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_two ______________________

self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>

    def test_two(self):
>       assert self.value == 1
E       assert 0 == 1
E        +  where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value

test_class_demo.py:9: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
1 failed, 1 passed in 0.12s

Beachten Sie, dass Attribute, die auf Klassenebene hinzugefügt werden, Klassenattribute sind, sodass sie zwischen Tests geteilt werden.

Gleitkommawerte mit pytest.approx vergleichen

pytest bietet auch eine Reihe von Dienstprogrammen, um das Schreiben von Tests zu erleichtern. Sie können zum Beispiel pytest.approx() verwenden, um Gleitkommawerte zu vergleichen, die kleine Rundungsfehler aufweisen können

# content of test_approx.py
import pytest


def test_sum():
    assert (0.1 + 0.2) == pytest.approx(0.3)

Dies vermeidet die Notwendigkeit manueller Toleranzprüfungen oder die Verwendung von math.isclose und funktioniert mit Skalaren, Listen und NumPy-Arrays.

Fordern Sie ein eindeutiges temporäres Verzeichnis für funktionale Tests an

pytest bietet Builtin-Fixtures/Funktionsargumente, um beliebige Ressourcen anzufordern, wie z. B. ein eindeutiges temporäres Verzeichnis

# content of test_tmp_path.py
def test_needsfiles(tmp_path):
    print(tmp_path)
    assert 0

Listen Sie den Namen tmp_path in der Signatur der Testfunktion auf, und pytest sucht nach einer Fixture-Fabrik und ruft diese auf, um die Ressource zu erstellen, bevor die Testfunktion aufgerufen wird. Bevor der Test ausgeführt wird, erstellt pytest ein temporäres Verzeichnis, das für jeden Testaufruf eindeutig ist.

$ pytest -q test_tmp_path.py
F                                                                    [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________

tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')

    def test_needsfiles(tmp_path):
        print(tmp_path)
>       assert 0
E       assert 0

test_tmp_path.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_needsfiles - assert 0
1 failed in 0.12s

Weitere Informationen zur Handhabung von temporären Verzeichnissen finden Sie unter Temporäre Verzeichnisse und Dateien.

Finden Sie mit dem Befehl heraus, welche Art von Builtin-pytest-Fixtures existieren

pytest --fixtures   # shows builtin and custom fixtures

Beachten Sie, dass dieser Befehl Fixtures mit führendem _ auslässt, es sei denn, die Option -v wird hinzugefügt.

Weiterlesen

Sehen Sie sich zusätzliche pytest-Ressourcen an, die Ihnen helfen, Tests für Ihren individuellen Workflow anzupassen