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
_pytest
Paket nicht beabsichtigt extern importiert werden. Der Versuch, dies zu tun, ohne zu wissen, was Sie tun, führt normalerweise dazu, dass das öffentliche pytest
Paket 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
_pytest
auf sichere Weise API, haben Sie , dies zu tun , bevor die Öffentlichkeit laufen pytest
Paket Lauf durch den externen py.test
Befehl. Das kannst du nicht in einem Plugin tun (z. B. einem conftest
Modul 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.test
test
- Monkey-Patches das Private
_pytest
API.
- Ruft die öffentliche
pytest.main()
Funktion auf, um den py.test
Befehl auszuführen .
Diese Antwort monkey-patches py.test's -s
und --capture=no
Optionen 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 test
Befehl 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- test
Befehl 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.