Wie kann ich die normale Druckausgabe sehen, die während des Pytest-Laufs erstellt wurde?

400

Manchmal möchte ich einfach einige Druckanweisungen in meinen Code einfügen und sehen, was ausgedruckt wird, wenn ich es ausübe. Meine übliche Art, es zu "trainieren", ist mit bestehenden Pytest-Tests. Aber wenn ich diese ausführe, sehe ich anscheinend keine Standardausgabe (zumindest nicht in PyCharm, meiner IDE).

Gibt es eine einfache Möglichkeit, die Standardausgabe während eines Pytest-Laufs anzuzeigen?

Des
quelle
Nur bei Misserfolg oder immer?
17
-s deaktiviert die Erfassung pro Test
hpk42
3
@ Delnan - Ich würde es gerne immer sehen
Des

Antworten:

565

Der -sSwitch deaktiviert die Erfassung pro Test.

hpk42
quelle
86
-s=--capture=no
Kochfelder
Die URL ist fehlerhaft. Vielleicht hilft dieser: docs.pytest.org/en/latest/capture.html
code_dredd
1
Dadurch wird die Ausgabe mit der Pytest-Ausgabe verschachtelt. Was Sie wahrscheinlich wollen, ist, dass Pytest die Ausgabe wie gewohnt erfasst und anzeigt, wenn Tests bestanden oder nicht bestanden werden. Siehe stackoverflow.com/a/59156707/369977
pR0Ps
51

In einem upvoted Kommentar auf die akzeptierte Antwort , Joe fragt:

Gibt es eine Möglichkeit, auf der Konsole zu drucken UND die Ausgabe so zu erfassen, dass sie im Junit-Bericht angezeigt wird?

Unter UNIX wird dies üblicherweise als Abschlag bezeichnet . Im Idealfall ist das Abschlagen und nicht das Erfassen die Standardeinstellung von py.test. Nicht ideal, weder py.test noch ein bestehendes Fremd py.test Plugin (... , die ich kenne, sowieso ) unterstützt Abschläge - trotz Python triviale Weise unterstützt teeing out-of-the-box .

Das Affen-Patchen von py.test, um etwas zu tun , das nicht unterstützt wird, ist nicht trivial. Warum? Weil:

  • Die meisten py.test Funktionalität hinter einem privaten gesperrtes _pytestPaket nicht beabsichtigt extern importiert werden. Der Versuch, dies zu tun, ohne zu wissen, was Sie tun, führt normalerweise dazu, dass das öffentliche pytestPaket zur Laufzeit unklare Ausnahmen auslöst. Vielen Dank, py.test. Wirklich robuste Architektur, die Sie dort haben.
  • Auch wenn Sie tun , herauszufinden , wie man den privaten Affen Patch _pytestauf sichere Weise API, haben Sie , dies zu tun , bevor die Öffentlichkeit laufen pytestPaket Lauf durch den externen py.testBefehl. Das kannst du nicht in einem Plugin tun (z. B. einem conftestModul der obersten Ebene in Ihrer Testsuite). Bis py.test träge dazu kommt, Ihr Plugin dynamisch zu importieren, ist jede py.test-Klasse, die Sie mit Affen-Patches versehen wollten, längst instanziiert - und Sie befehlen dies nicht Zugriff auf diese Instanz. Dies bedeutet, dass Sie den externen Befehl nicht mehr sicher ausführen können, wenn Sie möchten, dass Ihr Affen-Patch sinnvoll angewendet wird . Stattdessen müssen Sie die Ausführung dieses Befehls mit benutzerdefinierten Setuptools abschließen (in der Reihenfolge): py.testtest
    1. Monkey-Patches das Private _pytest API.
    2. Ruft die öffentliche pytest.main()Funktion auf, um den py.testBefehl auszuführen .

Diese Antwort monkey-patches py.test's -sund --capture=noOptionen zum Erfassen von stderr aber nicht stdout. Standardmäßig erfassen diese Optionen weder stderr noch stdout. Das ist natürlich nicht ganz so. Aber jede große Reise beginnt mit einem langwierigen Prequel, das jeder in fünf Jahren vergisst.

Warum das? Ich werde es dir jetzt sagen. Meine py.test-gesteuerte Testsuite enthält langsame Funktionstests. Das Anzeigen des Standardwerts dieser Tests ist hilfreich und beruhigend und verhindert, dass Leyceckillall -9 py.test nach etwas greift , wenn ein weiterer lang laufender Funktionstest wochenlang nichts tut. Das Anzeigen des stderr dieser Tests verhindert jedoch, dass py.test Ausnahme-Tracebacks bei Testfehlern meldet. Welches ist völlig nicht hilfreich. Daher zwingen wir py.test, stderr aber zu erfassen nicht stdout.

Bevor wir dazu kommen, wird in dieser Antwort davon ausgegangen, dass Sie bereits einen benutzerdefinierten testBefehl setuptools haben, der py.test aufruft. Wenn Sie dies nicht tun, lesen Sie den Unterabschnitt Manuelle Integration der gut geschriebenen Good Practices von py.test Seite.

Installieren Sie keinen Pytest-Runner , ein Setuptools-Plugin eines Drittanbieters, das einen benutzerdefinierten setuptools- testBefehl bereitstellt und auch py.test aufruft. Wenn pytest-running bereits installiert ist, müssen Sie wahrscheinlich dieses pip3-Paket deinstallieren und dann den oben verlinkten manuellen Ansatz anwenden.

Angenommen, Sie haben die oben hervorgehobenen Anweisungen in der manuellen Integration befolgt , sollte Ihre Codebasis jetzt eine PyTest.run_tests()Methode enthalten . Ändern Sie diese Methode so, dass sie ähnelt:

class PyTest(TestCommand):
             .
             .
             .
    def run_tests(self):
        # Import the public "pytest" package *BEFORE* the private "_pytest"
        # package. While importation order is typically ignorable, imports can
        # technically have side effects. Tragicomically, that is the case here.
        # Importing the public "pytest" package establishes runtime
        # configuration required by submodules of the private "_pytest" package.
        # The former *MUST* always be imported before the latter. Failing to do
        # so raises obtuse exceptions at runtime... which is bad.
        import pytest
        from _pytest.capture import CaptureManager, FDCapture, MultiCapture

        # If the private method to be monkey-patched no longer exists, py.test
        # is either broken or unsupported. In either case, raise an exception.
        if not hasattr(CaptureManager, '_getcapture'):
            from distutils.errors import DistutilsClassError
            raise DistutilsClassError(
                'Class "pytest.capture.CaptureManager" method _getcapture() '
                'not found. The current version of py.test is either '
                'broken (unlikely) or unsupported (likely).'
            )

        # Old method to be monkey-patched.
        _getcapture_old = CaptureManager._getcapture

        # New method applying this monkey-patch. Note the use of:
        #
        # * "out=False", *NOT* capturing stdout.
        # * "err=True", capturing stderr.
        def _getcapture_new(self, method):
            if method == "no":
                return MultiCapture(
                    out=False, err=True, in_=False, Capture=FDCapture)
            else:
                return _getcapture_old(self, method)

        # Replace the old with the new method.
        CaptureManager._getcapture = _getcapture_new

        # Run py.test with all passed arguments.
        errno = pytest.main(self.pytest_args)
        sys.exit(errno)

Führen Sie py.test wie folgt aus, um diesen Affen-Patch zu aktivieren:

python setup.py test -a "-s"

Stderr aber nicht stdout wird jetzt erfasst. Raffiniert!

Das Erweitern des obigen Affenfeldes auf Tee-Stdout und Stderr bleibt dem Leser als Übung mit einem Fass voller Freizeit.

Cecil Curry
quelle
33

Verwenden Sie beim Ausführen des Tests die -sOption. Alle print-Anweisungen in werden exampletest.pyauf der Konsole gedruckt, wenn der Test ausgeführt wird.

py.test exampletest.py -s
Sommerspaß
quelle
31

Laut Pytest-Dokumentation kann Version 3 von Pytest die Erfassung in einem Test vorübergehend 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')
Roman Susi
quelle
20

pytest erfasst den Standard aus einzelnen Tests und zeigt ihn nur unter bestimmten Bedingungen zusammen mit der Zusammenfassung der Tests an, die standardmäßig gedruckt werden.

Zusätzliche zusammenfassende Informationen können mit der Option '-r' angezeigt werden:

pytest -rP

zeigt die erfasste Ausgabe der bestandenen Tests.

pytest -rx

Zeigt die erfasste Ausgabe fehlgeschlagener Tests an (Standardverhalten).

Die Formatierung der Ausgabe ist mit -r schöner als mit -s.

Sunthar
quelle
2
Dies ist die eigentliche Antwort, nach der ich gesucht habe! Vielen Dank. (Mit kommen die stdout AFTER den Testergebnissen ist erwünscht , wenn sie verschachtelt sind, wobei die gedruckten Linien Wert verlieren..)
bossylobster
18

Versuchen Sie pytest -s -v test_login.pyfür weitere Informationen in der Konsole.

-v es ist kurz --verbose

-s bedeutet "Alle Erfassungen deaktivieren"



Alex Makarenko
quelle
1
Wenn Sie die Datei pytest.ini verwenden, können Sie Folgendes verwenden: addopts = -s -v python_files = test_login.py
timj98
4

Wenn Sie PyCharm IDE verwenden, können Sie diesen einzelnen Test oder alle Tests über die Symbolleiste Ausführen ausführen. Das Fenster "Ausführen" zeigt die von Ihrer Anwendung generierte Ausgabe an, und Sie können alle darin enthaltenen Druckanweisungen als Teil der Testausgabe anzeigen.

Zwillinge Jain
quelle
Wissen Sie, wie PyCharm gedruckt wird, während der Test ausgeführt wird? (anstatt nachdem der Test bestanden wurde)
Alexandre Huat
3

pytest --capture=tee-syswurde kürzlich hinzugefügt. Sie können die Ausgabe auf stdout / err erfassen und anzeigen.

meonstackexchange
quelle
-4

Die anderen Antworten funktionieren nicht. Die einzige Möglichkeit, die erfasste Ausgabe anzuzeigen, ist die Verwendung des folgenden Flags:

pytest --show-capture all

aaa90210
quelle
6
--show-capture=allist der Standardwert. Das Hinzufügen hat keine Auswirkungen.
Hacke