Über Fixtures¶
Siehe auch
Siehe auch
pytest Fixtures sind explizit, modular und skalierbar konzipiert.
Was Fixtures sind¶
Beim Testen stellt ein Fixture einen definierten, zuverlässigen und konsistenten Kontext für die Tests bereit. Dies kann die Umgebung (z. B. eine Datenbank, die mit bekannten Parametern konfiguriert ist) oder Inhalte (wie ein Datensatz) umfassen.
Fixtures definieren die Schritte und Daten, die die arrange Phase eines Tests ausmachen (siehe Anatomie eines Tests). In pytest sind dies Funktionen, die Sie zu diesem Zweck definieren. Sie können auch verwendet werden, um die act Phase eines Tests zu definieren; dies ist eine leistungsstarke Technik für die Gestaltung komplexerer Tests.
Die von Fixtures eingerichteten Dienste, Zustände oder anderen Betriebsumgebungen werden von Testfunktionen über Argumente aufgerufen. Für jedes von einer Testfunktion verwendete Fixture gibt es typischerweise einen Parameter (benannt nach dem Fixture) in der Definition der Testfunktion.
Wir können pytest mitteilen, dass eine bestimmte Funktion ein Fixture ist, indem wir sie mit @pytest.fixture dekorieren. Hier ist ein einfaches Beispiel, wie ein Fixture in pytest aussehen könnte
import pytest
class Fruit:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
@pytest.fixture
def my_fruit():
return Fruit("apple")
@pytest.fixture
def fruit_basket(my_fruit):
return [Fruit("banana"), my_fruit]
def test_my_fruit_in_basket(my_fruit, fruit_basket):
assert my_fruit in fruit_basket
Tests sind auch nicht auf ein einzelnes Fixture beschränkt. Sie können von beliebig vielen Fixtures abhängen, und Fixtures können auch andere Fixtures verwenden. Hier glänzt das Fixture-System von pytest wirklich.
Verbesserungen gegenüber xUnit-Style Setup/Teardown-Funktionen¶
pytest Fixtures bieten dramatische Verbesserungen gegenüber dem klassischen xUnit-Stil von Setup/Teardown-Funktionen
Fixtures haben explizite Namen und werden durch die Deklaration ihrer Verwendung von Testfunktionen, Modulen, Klassen oder ganzen Projekten aktiviert.
Fixtures werden modular implementiert, da jeder Fixture-Name eine Fixture-Funktion auslöst, die selbst andere Fixtures verwenden kann.
Das Fixture-Management skaliert von einfachen Unit- bis hin zu komplexen Funktionstests, ermöglicht die Parametrisierung von Fixtures und Tests gemäß Konfigurations- und Komponentenoptionen oder die Wiederverwendung von Fixtures über Funktions-, Klassen-, Modul- oder gesamte Testsitzungsumgebungen hinweg.
Teardown-Logik kann einfach und sicher verwaltet werden, unabhängig davon, wie viele Fixtures verwendet werden, ohne dass Fehler sorgfältig von Hand behandelt oder die Reihenfolge der Bereinigungsschritte mikroverwaltet werden muss.
Darüber hinaus unterstützt pytest weiterhin So implementieren Sie xunit-Style Setup. Sie können beide Stile mischen und schrittweise vom klassischen zum neuen Stil übergehen, wie Sie möchten. Sie können auch mit vorhandenen unittest.TestCase-Stilen beginnen.
Fixture-Fehler¶
pytest tut sein Bestes, um alle Fixtures für einen bestimmten Test in einer linearen Reihenfolge anzuordnen, damit es sehen kann, welches Fixture zuerst, zweitens, drittens usw. kommt. Wenn jedoch ein früheres Fixture ein Problem hat und eine Ausnahme auslöst, stoppt pytest die Ausführung von Fixtures für diesen Test und markiert den Test als fehlerhaft.
Wenn ein Test als fehlerhaft markiert ist, bedeutet das nicht, dass der Test fehlgeschlagen ist. Es bedeutet lediglich, dass der Test nicht einmal versucht werden konnte, da etwas, von dem er abhing, ein Problem hatte.
Dies ist einer der Gründe, warum es eine gute Idee ist, für einen bestimmten Test so viele unnötige Abhängigkeiten wie möglich zu entfernen. Auf diese Weise verursacht ein Problem bei etwas Unzusammenhängendem kein unvollständiges Bild davon, was Probleme haben könnte oder auch nicht.
Hier ist ein kurzes Beispiel zur Veranschaulichung
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def append_first(order):
order.append(1)
@pytest.fixture
def append_second(order, append_first):
order.extend([2])
@pytest.fixture(autouse=True)
def append_third(order, append_second):
order += [3]
def test_order(order):
assert order == [1, 2, 3]
Wenn aus irgendeinem Grund order.append(1) einen Fehler hätte und eine Ausnahme auslösen würde, könnten wir nicht wissen, ob order.extend([2]) oder order += [3] ebenfalls Probleme hätten. Nachdem append_first eine Ausnahme ausgelöst hat, wird pytest keine weiteren Fixtures für test_order ausführen und wird auch nicht einmal versuchen, test_order selbst auszuführen. Die einzigen Dinge, die ausgeführt worden wären, wären order und append_first.
Hinweis zur Fixture-Bereinigung¶
pytest führt keine spezielle Verarbeitung für SIGTERM und SIGQUIT Signale durch (SIGINT wird natürlich vom Python-Laufzeitsystem über KeyboardInterrupt behandelt), sodass Fixtures, die externe Ressourcen verwalten, die beim Beenden des Python-Prozesses (durch diese Signale) gelöscht werden müssen, Ressourcenlecks verursachen können.
Der Grund, warum pytest diese Signale nicht zur Fixture-Bereinigung verarbeitet, ist, dass Signal-Handler global sind und ihre Änderung den auszuführenden Code stören könnte.
Wenn Fixtures in Ihrer Suite besondere Sorgfalt in Bezug auf die Beendigung in diesen Szenarien benötigen, lesen Sie diesen Kommentar im Issue-Tracker für einen möglichen Workaround.