Wie stdout/stderr-Ausgabe erfasst wird¶
Pytest fängt stdout und stderr wie durch das Kommandozeilenargument --capture= oder durch die Verwendung von Fixtures konfiguriert ab. Das Flag --capture= konfiguriert die Berichterstattung, während die Fixtures eine feinere Kontrolle ermöglichen und die Inspektion der Ausgabe während der Tests erlauben. Die Berichte können mit dem -r Flag angepasst werden.
Standardverhalten bei der Erfassung von stdout/stderr/stdin¶
Während der Testausführung wird jede an stdout und stderr gesendete Ausgabe erfasst. Wenn eine Test- oder eine Setup-Methode fehlschlägt, wird ihre entsprechende erfasste Ausgabe normalerweise zusammen mit dem Fehlertraceback angezeigt (dieses Verhalten kann durch die Kommandozeilenoption --show-capture konfiguriert werden).
Zusätzlich wird stdin auf ein "null"-Objekt gesetzt, das bei Leseversuchen fehlschlägt, da es selten erwünscht ist, auf interaktive Eingaben zu warten, wenn automatisierte Tests ausgeführt werden.
Standardmäßig erfolgt die Erfassung durch Abfangen von Schreibvorgängen auf Low-Level-Dateideskriptoren. Dies ermöglicht die Erfassung von Ausgaben einfacher Print-Anweisungen sowie von Ausgaben eines durch einen Test gestarteten Subprozesses.
Festlegen von Erfassungsmethoden oder Deaktivieren der Erfassung¶
Es gibt drei Möglichkeiten, wie pytest Erfassung durchführen kann:
fd(File Descriptor) Level Erfassung (Standard): Alle Schreibvorgänge, die auf die Betriebssystem-Dateideskriptoren 1 und 2 gehen, werden erfasst.sysLevel Erfassung: Nur Schreibvorgänge auf die Python-Dateiensys.stdoutundsys.stderrwerden erfasst. Es erfolgt keine Erfassung von Schreibvorgängen auf Dateideskriptoren.tee-sysErfassung: Python-Schreibvorgänge aufsys.stdoutundsys.stderrwerden erfasst, jedoch werden die Schreibvorgänge auch an die tatsächlichensys.stdoutundsys.stderrweitergeleitet. Dies ermöglicht es, Ausgaben "live zu drucken" und für Plugin-Zwecke, wie z. B. junitxml (neu in pytest 5.4), zu erfassen.
Sie können die Mechanismen zur Erfassung von Ausgaben über die Kommandozeile beeinflussen.
pytest -s # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd # also point filedescriptors 1 and 2 to temp file
pytest --capture=tee-sys # combines 'sys' and '-s', capturing sys.stdout/stderr
# and passing it along to the actual sys.stdout/stderr
Verwendung von Print-Anweisungen zur Fehlersuche¶
Ein Hauptvorteil der Standarderfassung von stdout/stderr-Ausgaben ist, dass Sie Print-Anweisungen zur Fehlersuche verwenden können.
# content of test_module.py
def setup_function(function):
print("setting up", function)
def test_func1():
assert True
def test_func2():
assert False
und die Ausführung dieses Moduls zeigt Ihnen genau die Ausgabe der fehlschlagenden Funktion und unterdrückt die andere.
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items
test_module.py .F [100%]
================================= FAILURES =================================
________________________________ test_func2 ________________________________
def test_func2():
> assert False
E assert False
test_module.py:12: AssertionError
-------------------------- Captured stdout setup ---------------------------
setting up <function test_func2 at 0xdeadbeef0001>
========================= short test summary info ==========================
FAILED test_module.py::test_func2 - assert False
======================= 1 failed, 1 passed in 0.12s ========================
Zugriff auf erfasste Ausgabe aus einer Testfunktion¶
Die Fixtures capsys, capteesys, capsysbinary, capfd und capfdbinary ermöglichen den Zugriff auf die während der Testausführung erzeugte stdout/stderr-Ausgabe.
Hier ist eine Beispiel-Testfunktion, die einige ausgabebezogene Prüfungen durchführt.
def test_myoutput(capsys): # or use "capfd" for fd-level
print("hello")
sys.stderr.write("world\n")
captured = capsys.readouterr()
assert captured.out == "hello\n"
assert captured.err == "world\n"
print("next")
captured = capsys.readouterr()
assert captured.out == "next\n"
Der Aufruf readouterr() macht einen Schnappschuss der bisherigen Ausgabe – und die Erfassung wird fortgesetzt. Nach Beendigung der Testfunktion werden die ursprünglichen Streams wiederhergestellt. Die Verwendung von capsys auf diese Weise befreit Ihren Test von der Notwendigkeit, sich um das Setzen/Zurücksetzen von Ausgabeströmen kümmern zu müssen, und interagiert gut mit der eigenen Erfassung von Pytest pro Test.
Der Rückgabewert von readouterr() ist ein namedtuple mit zwei Attributen: out und err.
Wenn der zu testende Code nicht-textuelle Daten (bytes) schreibt, können Sie dies mit dem Fixture capsysbinary erfassen, das stattdessen bytes von der Methode readouterr zurückgibt.
Wenn Sie auf Dateideskriptor-Ebene erfassen möchten, können Sie das Fixture capfd verwenden, das die exakt gleiche Schnittstelle bietet, aber auch Ausgaben von Bibliotheken oder Subprozessen erfassen kann, die direkt auf Betriebssystem-Level-Ausgabeströme (FD1 und FD2) schreiben. Ähnlich wie capsysbinary kann capfdbinary verwendet werden, um bytes auf Dateideskriptor-Ebene zu erfassen.
Um die Erfassung innerhalb eines Tests vorübergehend zu deaktivieren, verfügen die Erfassungs-Fixtures über eine Methode disabled(), die als Kontextmanager verwendet werden kann, um die Erfassung innerhalb des with-Blocks zu deaktivieren.
def test_disabling_capturing(capsys):
print("this output is captured")
with capsys.disabled():
print("output not captured, going directly to sys.stdout")
print("this output is also captured")