In einem hochgestufter Kommentar zum akzeptierte Antwort , Joe fragt:
Gibt es eine Möglichkeit, in die Konsole zu drucken UND die Ausgabe erfassen, damit sie im Junit-Bericht erscheint?
Unter UNIX wird dies üblicherweise als Abschlag . Idealerweise wäre der Standard von py.test eher das Testen als das Erfassen. Nicht ideal ist, dass weder py.test noch ein bestehendes py.test-Plugin eines Drittanbieters (... die ich kenne, jedenfalls ) unterstützt Abschläge - obwohl Python trivialerweise Abschläge unterstützt sofort einsatzbereit .
Monkey-Parcheando py.test zu tun alles nicht unterstützt wird, ist nicht trivial. Warum? Weil:
- Die meisten py.test-Funktionen sind hinter einer privaten
_pytest
Paket no die zur externen Einfuhr bestimmt sind. Der Versuch, dies zu tun, ohne zu wissen, was man tut, führt in der Regel dazu, dass die öffentliche pytest
Paket, das obskure Ausnahmen zur Laufzeit auslöst. Vielen Dank, py.test. Wirklich robuste Architektur haben Sie dort.
- Auch wenn Sie tun herausfinden, wie man den privaten
_pytest
API auf sichere Weise zu nutzen, müssen Sie dies tun antes de Leitung der Öffentlichkeit pytest
Paket, das von dem externen py.test
Befehl. Sie kann nicht dies in einem Plugin zu tun (z. B. in einem Top-Level conftest
Modul in Ihrer Testsuite). Bis py.test sich dazu durchringt, Ihr Plugin dynamisch zu importieren, ist jede py.test-Klasse, die Sie einbauen wollten, schon längst instanziiert - und Sie müssen no Zugang zu dieser Instanz haben. Dies bedeutet, dass Sie, wenn Sie wollen, dass Ihr Monkey-Patch sinnvoll angewendet wird, nicht mehr sicher die externe py.test
Befehl. Stattdessen müssen Sie die Ausführung dieses Befehls mit einem benutzerdefinierten setuptools verpacken test
Befehl (in dieser Reihenfolge):
- Affenflicken das Private
_pytest
API.
- Ruft die Öffentlichkeit an
pytest.main()
Funktion zur Ausführung der py.test
Befehl.
Diese Antwort patcht die py.test's -s
y --capture=no
Optionen, um stderr zu erfassen, aber no stdout. Standardmäßig erfassen diese Optionen weder stderr noch stdout. Das ist natürlich nicht wirklich ein Abschlag. Aber jede große Reise beginnt mit einer mühsamen Vorgeschichte, die jeder in fünf Jahren vergessen hat.
Warum dies tun? Ich werde es Ihnen jetzt sagen. Meine py.test-driven Testsuite enthält langsame funktionale Tests. Die Anzeige des stdout dieser Tests ist hilfreich und beruhigend und verhindert leycec vom Griff nach killall -9 py.test
wenn wieder einmal ein langwieriger Funktionstest wochenlang nichts bringt. Die Anzeige der stderr dieser Tests verhindert jedoch, dass py.test bei Testfehlern Ausnahme-Tracebacks ausgibt. Das ist absolut nicht hilfreich. Daher zwingen wir py.test dazu, stderr zu erfassen, aber no stdout.
Bevor wir dazu kommen, geht diese Antwort davon aus, dass Sie bereits ein benutzerdefiniertes setuptools test
Befehl, der py.test aufruft. Wenn Sie das nicht tun, lesen Sie die Manuelle Integration Unterabschnitt von py.test's gut geschriebenem Bewährte Praktiken Seite.
Do no installieren pytest-runner ein Setuptools-Plugin eines Drittanbieters, das ein benutzerdefiniertes Setuptools test
Befehl, der auch py.test aufruft. Wenn pytest-runner bereits installiert ist, müssen Sie wahrscheinlich dieses pip3-Paket deinstallieren und dann den oben verlinkten manuellen Ansatz anwenden.
Angenommen, Sie haben die Anweisungen in Manuelle Integration wie oben hervorgehoben, sollte Ihre Codebasis nun eine PyTest.run_tests()
Methode. Ändern Sie diese Methode so, dass sie ähnlich aussieht:
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)
Um diesen Monkey-Patch zu aktivieren, führen Sie py.test wie folgt aus:
python setup.py test -a "-s"
Stderr aber no stdout wird nun aufgezeichnet. Raffiniert!
Die Erweiterung des obigen Monkey-Patches auf stdout und stderr wird als Übung dem Leser überlassen, der ein Fass voll Freizeit hat.