Erste Schritte¶
Installieren von pytest¶
Führen Sie den folgenden Befehl in Ihrer Kommandozeile aus
pip install -U pytest
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
„So rufen Sie pytest auf“ für Beispiele zur Befehlszeilenaufrufung
„So verwenden Sie pytest mit einer vorhandenen Testsuite“ für die Arbeit mit vorhandenen Tests
„So markieren Sie Testfunktionen mit Attributen“ für Informationen über den
pytest.mark-Mechanismus„Fixture-Referenz“ für die Bereitstellung einer funktionalen Basis für Ihre Tests
„Plugins schreiben“ für die Verwaltung und das Schreiben von Plugins
„Gute Integrationspraktiken“ für virtuelle Umgebungen und Testlayouts