Protokollierung innerhalb von Pytest-Tests

93

Ich möchte einige Protokollierungsanweisungen in die Testfunktion einfügen, um einige Statusvariablen zu untersuchen.

Ich habe das folgende Code-Snippet:

import pytest,os
import logging

logging.basicConfig(level=logging.DEBUG)
mylogger = logging.getLogger()

#############################################################################

def setup_module(module):
    ''' Setup for the entire module '''
    mylogger.info('Inside Setup')
    # Do the actual setup stuff here
    pass

def setup_function(func):
    ''' Setup for test functions '''
    if func == test_one:
        mylogger.info(' Hurray !!')

def test_one():
    ''' Test One '''
    mylogger.info('Inside Test 1')
    #assert 0 == 1
    pass

def test_two():
    ''' Test Two '''
    mylogger.info('Inside Test 2')
    pass

if __name__ == '__main__':
    mylogger.info(' About to start the tests ')
    pytest.main(args=[os.path.abspath(__file__)])
    mylogger.info(' Done executing the tests ')

Ich erhalte folgende Ausgabe:

[bmaryada-mbp:/Users/bmaryada/dev/platform/main/proto/tests/tpch $]python minitest.py
INFO:root: About to start the tests 
======================================================== test session starts =========================================================
platform darwin -- Python 2.6.2 -- pytest-2.0.0
collected 2 items 

minitest.py ..

====================================================== 2 passed in 0.01 seconds ======================================================
INFO:root: Done executing the tests 

Beachten Sie, dass nur die Protokollierungsnachrichten vom '__name__ == __main__'Block an die Konsole übertragen werden.

Gibt es eine Möglichkeit, pytestdie Protokollierung auch von Testmethoden an die Konsole zu erzwingen ?

Superselector
quelle
3
Sie können sich diese Antwort ansehen , die vom Ersteller von py.test veröffentlicht wurde. Er schlägt ein Pytest-Plugin vor, das ein hohes Maß an Vielseitigkeit bietet.
chb

Antworten:

30

Funktioniert für mich, hier ist die Ausgabe, die ich bekomme: [snip -> Beispiel war falsch]

Bearbeiten: Es scheint, dass Sie die -sOption an py.test übergeben müssen, damit stdout nicht erfasst wird. Hier (py.test nicht installiert) war es ausreichend zu verwenden python pytest.py -s pyt.py.

Für Ihren Code, alles , was Sie brauchen , ist zu passieren -sin argsan main:

 pytest.main(args=['-s', os.path.abspath(__file__)])

Weitere Informationen zum Erfassen der Ausgabe finden Sie in der Dokumentation zu py.test .

TryPyPy
quelle
Es tut uns leid. Ich habe den Code in Eile eingefügt. Bitte entfernen Sie die 'assert 0 == 1' aus der 'test_one'-Funktion, um das' Problem 'zu bemerken. Nur wenn ein Fehler vorliegt (den ich durch eine falsche Behauptung erzwungen habe), scheint py.test die Protokollinformationen zu drucken.
Superselector
Kein Problem, ich fand heraus, wie man es in der Kommandozeile behebt und suchte nach einem programmatischen Weg.
TryPyPy
1
Sie können die Protokollausgabe auch in eine Datei umleiten, anstatt in den impliziten Standard-Stderr.
HPK42
@superselector hpk42 ist der py.test Typ, hör zu. IIUC, in Ihrem Code wäre es logging.basicConfig(filename="somelog.txt", level=logging.DEBUG).
TryPyPy
125

Seit Version 3.3 wird pytestdie Live-Protokollierung unterstützt. Dies bedeutet, dass alle in Tests ausgegebenen Protokolldatensätze sofort auf dem Terminal gedruckt werden. Die Funktion ist im Abschnitt Live-Protokolle dokumentiert . Die Live-Protokollierung ist standardmäßig deaktiviert. Um es zu aktivieren, stellen Sie log_cli = 1in der pyproject.toml1 oder pytest.ini2 Konfiguration ein. Die Live-Protokollierung unterstützt das Senden an Terminal und Datei. Die entsprechenden Optionen ermöglichen das Anpassen von Datensätzen:

Terminal:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

Datei:

  • log_file
  • log_file_level
  • log_file_format
  • log_file_date_format

Hinweis : Das log_cliFlag kann nicht über die Befehlszeile übergeben werden und muss gesetzt sein pytest.ini. Alle anderen Optionen können sowohl über die Befehlszeile übergeben als auch in der Konfigurationsdatei festgelegt werden. Wie Kévin Barré in diesem Kommentar hervorhob, kann das Überschreiben von INI-Optionen über die Befehlszeile über die -o/--overrideOption erfolgen. Anstatt also zu erklären log_cliin pytest.ini, können Sie einfach anrufen:

$ pytest -o log_cli=true ...

Beispiele

Einfache Testdatei zur Demonstration:

# test_spam.py

import logging

LOGGER = logging.getLogger(__name__)


def test_eggs():
    LOGGER.info('eggs info')
    LOGGER.warning('eggs warning')
    LOGGER.error('eggs error')
    LOGGER.critical('eggs critical')
    assert True

Wie Sie sehen, ist keine zusätzliche Konfiguration erforderlich. pytestDer Logger wird automatisch eingerichtet, basierend auf den Optionen, die in der pytest.iniBefehlszeile angegeben oder von dieser übergeben werden.

Live-Protokollierung auf Terminal, INFOEbene, ausgefallene Ausgabe

Konfiguration in pyproject.toml:

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "INFO"
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"

Die identische Konfiguration im Legacy pytest.ini:

[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S

Ausführen des Tests:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
2018-08-01 14:33:20 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:33:20 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:33:20 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:33:20 [CRITICAL] eggs critical (test_spam.py:10)
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

Live-Protokollierung in Terminal und Datei, nur Nachricht und CRITICALEbene im Terminal, ausgefallene Ausgabe in pytest.logDatei

Konfiguration in pyproject.toml:

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "CRITICAL"
log_cli_format = "%(message)s"

log_file = "pytest.log"
log_file_level = "DEBUG"
log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_file_date_format = "%Y-%m-%d %H:%M:%S"

Die identische Konfiguration im Legacy pytest.ini:

[pytest]
log_cli = 1
log_cli_level = CRITICAL
log_cli_format = %(message)s

log_file = pytest.log
log_file_level = DEBUG
log_file_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_file_date_format=%Y-%m-%d %H:%M:%S

Testlauf:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
eggs critical
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

$ cat pytest.log
2018-08-01 14:38:09 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:38:09 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:38:09 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:38:09 [CRITICAL] eggs critical (test_spam.py:10)

1 pyproject.toml wird seit Version 6.0 unterstützt und ist die beste Option IMO. Siehe PEP 518 für die technischen Daten.

2 Obwohl Sie auch pytestin setup.cfgdiesem [tool:pytest]Abschnitt konfigurieren können , sollten Sie dies nicht tun, wenn Sie ein benutzerdefiniertes Live-Protokollierungsformat bereitstellen möchten. Das Lesen anderer Tools setup.cfgbehandelt möglicherweise Dinge wie %(message)sString-Interpolation und schlägt fehl. Die beste Wahl ist pyproject.tomlohnehin die Verwendung. Wenn Sie jedoch gezwungen sind, das alte Ini-Format zu verwenden, halten Sie sich an pytest.ini, um Fehler zu vermeiden.

hoefling
quelle
19
log_cliIn Bezug auf den Hinweis, der in pytest.ini enthalten sein muss , können Sie anscheinend die -oOption verwenden, um den Wert in der Befehlszeile zu überschreiben. pytest -o log_cli=true --log-cli-level=DEBUGfunktioniert bei mir.
Kévin Barré
@ KévinBarré sehr netter Kommentar und ein sehr nützlicher Hinweis im Allgemeinen, danke! Die Antwort wurde aktualisiert.
hoefling
Dies ist definitiv die richtige Antwort bei der Verwendung der Protokollierung. Obwohl ich gerne zwischen Protokollen, die sich in den Tests befinden, und Protokollen, die sich im zu testenden System befinden , unterscheiden möchte, die separat betrachtet werden sollten.
CMCDragonkai
@CMCDragonkai pytestist in dieser Angelegenheit leider etwas eingeschränkt. Dies sollte jedoch mit einer speziellen Protokollierungskonfiguration für Tests in Ihrer App möglich sein. Deaktivieren Sie die Weitergabe in Ihren Loggern und fügen Sie einen "Testhandler" hinzu, der sich in einer angegebenen Datei protokolliert. Auf diese Weise werden pytestnur Datensätze protokolliert, die aus Tests stammen, während der benutzerdefinierte Handler sich um die SuT-Protokolle kümmert.
hoefling
1
@OfekAgmon Wenn Sie die pytestAusgabe speichern möchten , können Sie das --result-logArgument verwenden (obwohl es veraltet ist, sind hier die Alternativen ). Sie können die pytestAusgabe und die Live-Protokollierungsausgabe jedoch nicht in derselben Datei speichern.
hoefling