From 7ea5a22657027d87e7b35f456e9b044a097c910e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Hovm=C3=B6ller?= Date: Mon, 15 Jan 2018 15:01:01 +0100 Subject: [PATCH 1/2] Access captures logs in teardown --- AUTHORS | 1 + _pytest/logging.py | 12 ++++++++++++ changelog/3117.feature | 1 + doc/en/logging.rst | 9 +++++++++ testing/logging/test_fixture.py | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+) create mode 100644 changelog/3117.feature diff --git a/AUTHORS b/AUTHORS index 862378be9f5..8d981ae9ad5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,6 +9,7 @@ Ahn Ki-Wook Alexander Johnson Alexei Kozlenok Anatoly Bubenkoff +Anders Hovmöller Andras Tim Andreas Zeidler Andrzej Ostrowski diff --git a/_pytest/logging.py b/_pytest/logging.py index 9e82e801d97..27cea16678e 100644 --- a/_pytest/logging.py +++ b/_pytest/logging.py @@ -128,6 +128,13 @@ def __init__(self, item): def handler(self): return self._item.catch_log_handler + def get_handler(self, when): + """ + Get the handler for a specified state of the tests. + Valid values for the when parameter are: 'setup', 'call' and 'teardown'. + """ + return self._item.catch_log_handlers.get(when) + @property def text(self): """Returns the log text.""" @@ -287,11 +294,16 @@ def _runtest_for(self, item, when): """Implements the internals of pytest_runtest_xxx() hook.""" with catching_logs(LogCaptureHandler(), formatter=self.formatter) as log_handler: + if not hasattr(item, 'catch_log_handlers'): + item.catch_log_handlers = {} + item.catch_log_handlers[when] = log_handler item.catch_log_handler = log_handler try: yield # run test finally: del item.catch_log_handler + if when == 'teardown': + del item.catch_log_handlers if self.print_logs: # Add a captured log section to the report. diff --git a/changelog/3117.feature b/changelog/3117.feature new file mode 100644 index 00000000000..b232dce338e --- /dev/null +++ b/changelog/3117.feature @@ -0,0 +1 @@ +New member on the `_item` member of the `caplog` fixture: `catch_log_handlers`. This contains a dict for the logs for the different stages of the test (setup, call, teardown). So to access the logs for the setup phase in your tests you can get to them via `caplog._item.catch_log_handlers`. diff --git a/doc/en/logging.rst b/doc/en/logging.rst index e3bf5603887..9a6df84844f 100644 --- a/doc/en/logging.rst +++ b/doc/en/logging.rst @@ -190,3 +190,12 @@ option names are: * ``log_file_level`` * ``log_file_format`` * ``log_file_date_format`` + +Accessing logs from other test stages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``caplop.records`` fixture contains records from the current stage only. So +inside the setup phase it contains only setup logs, same with the call and +teardown phases. To access logs from other stages you can use +``caplog.get_handler('setup').records``. Valid stages are ``setup``, ``call`` +and ``teardown``. diff --git a/testing/logging/test_fixture.py b/testing/logging/test_fixture.py index c27b31137ff..1357dcf361b 100644 --- a/testing/logging/test_fixture.py +++ b/testing/logging/test_fixture.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import logging +import pytest logger = logging.getLogger(__name__) sublogger = logging.getLogger(__name__ + '.baz') @@ -68,3 +69,23 @@ def test_clear(caplog): assert len(caplog.records) caplog.clear() assert not len(caplog.records) + + +@pytest.fixture +def logging_during_setup_and_teardown(caplog): + logger.info('a_setup_log') + yield + logger.info('a_teardown_log') + assert [x.message for x in caplog.get_handler('teardown').records] == ['a_teardown_log'] + + +def test_caplog_captures_for_all_stages(caplog, logging_during_setup_and_teardown): + assert not caplog.records + assert not caplog.get_handler('call').records + logger.info('a_call_log') + assert [x.message for x in caplog.get_handler('call').records] == ['a_call_log'] + + assert [x.message for x in caplog.get_handler('setup').records] == ['a_setup_log'] + + # This reachers into private API, don't use this type of thing in real tests! + assert set(caplog._item.catch_log_handlers.keys()) == {'setup', 'call'} From c4c968fe6979cc2ca7c321b8a2966b7ee52f0430 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 20 Jan 2018 11:14:09 -0200 Subject: [PATCH 2/2] Reword CHANGELOG after introduction of caplog.get_handler() --- changelog/3117.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/3117.feature b/changelog/3117.feature index b232dce338e..17c64123fdd 100644 --- a/changelog/3117.feature +++ b/changelog/3117.feature @@ -1 +1 @@ -New member on the `_item` member of the `caplog` fixture: `catch_log_handlers`. This contains a dict for the logs for the different stages of the test (setup, call, teardown). So to access the logs for the setup phase in your tests you can get to them via `caplog._item.catch_log_handlers`. +New ``caplog.get_handler(when)`` method which provides access to the underlying ``Handler`` class used to capture logging during each testing stage, allowing users to obtain the captured records during ``"setup"`` and ``"teardown"`` stages.