Spec-Zone.ru › pytest

Как управлять журналированием

pytest автоматически перехватывает сообщения журнала уровня WARNING и выше и отображает их в отдельном разделе для каждого неудачного теста так же, как перехваченные stdout и stderr.

Запуск без параметров:

pytest

Неудачные тесты отображаются следующим образом:

----------------------- Captured stdlog call ----------------------
test_reporting.py    26 WARNING  text going to logger
----------------------- Captured stdout call ----------------------
text going to stdout
----------------------- Captured stderr call ----------------------
text going to stderr
==================== 2 failed in 0.02 seconds =====================

По умолчанию для каждого перехваченного сообщения журнала отображаются модуль, номер строки, уровень журнала и сообщение.

При необходимости формат журнала и даты можно задать в любом формате, поддерживаемом модулем logging, передав соответствующие параметры форматирования:

pytest --log-format="%(asctime)s %(levelname)s %(message)s" \
        --log-date-format="%Y-%m-%d %H:%M:%S"

Неудачные тесты отображаются следующим образом:

----------------------- Captured stdlog call ----------------------
2010-04-10 14:48:44 WARNING text going to logger
----------------------- Captured stdout call ----------------------
text going to stdout
----------------------- Captured stderr call ----------------------
text going to stderr
==================== 2 failed in 0.02 seconds =====================

Эти параметры также можно настроить с помощью файла конфигурации:

toml

[pytest]
log_format = "%(asctime)s %(levelname)s %(message)s"
log_date_format = "%Y-%m-%d %H:%M:%S"

ini

[pytest]
log_format = %(asctime)s %(levelname)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S

Отдельные регистраторы можно отключить с помощью --log-disable={logger_name}. Этот аргумент можно передавать несколько раз:

pytest --log-disable=main --log-disable=testing

Кроме того, можно полностью отключить вывод перехваченного содержимого (stdout, stderr и журналы) для неудачных тестов с помощью:

pytest --show-capture=no

Фикстура caplog

В тестах можно изменить уровень журнала для перехватываемых сообщений. Это поддерживается фикстурой caplog:

def test_foo(caplog):
    caplog.set_level(logging.INFO)

По умолчанию уровень задаётся для корневого регистратора, но для удобства можно задать уровень и для любого другого регистратора:

def test_foo(caplog):
    caplog.set_level(logging.CRITICAL, logger="root.baz")

Установленные уровни журнала автоматически восстанавливаются в конце теста.

Также можно использовать менеджер контекста, чтобы временно изменить уровень журнала внутри блока with:

def test_bar(caplog):
    with caplog.at_level(logging.INFO):
        pass

И снова: по умолчанию меняется уровень корневого регистратора, но вместо него можно изменить уровень любого другого регистратора:

def test_bar(caplog):
    with caplog.at_level(logging.CRITICAL, logger="root.baz"):
        pass

Наконец, все журналы, отправленные регистратору во время выполнения теста, доступны через фикстуру в виде экземпляров logging.LogRecord и итогового текста журнала. Это удобно, если нужно проверить содержимое сообщения:

def test_baz(caplog):
    func_under_test()
    for record in caplog.records:
        assert record.levelname != "CRITICAL"
    assert "wally" not in caplog.text

Список всех доступных атрибутов записей журнала см. в классе logging.LogRecord.

Также можно воспользоваться record_tuples, если нужно лишь убедиться, что под заданным именем регистратора были зарегистрированы определённые сообщения с заданным уровнем и текстом:

def test_foo(caplog):
    logging.getLogger().info("boo %s", "arg")

    assert caplog.record_tuples == [("root", logging.INFO, "boo arg")]

В тесте можно вызвать caplog.clear(), чтобы сбросить перехваченные записи журнала:

def test_something_with_clearing_records(caplog):
    some_method_that_creates_log_records()
    caplog.clear()
    your_test_method()
    assert ["Foo"] == [rec.message for rec in caplog.records]

Атрибут caplog.records содержит записи только текущего этапа, поэтому на этапе setup он содержит только журналы настройки; то же относится к этапам call и teardown.

Чтобы получить доступ к журналам других этапов, используйте метод caplog.get_records(when). Например, если нужно убедиться, что тесты, использующие определённую фикстуру, никогда не регистрируют предупреждения, во время завершения работы можно проверить записи этапов setup и call следующим образом:

@pytest.fixture
def window(caplog):
    window = create_window()
    yield window
    for when in ("setup", "call"):
        messages = [
            x.message for x in caplog.get_records(when) if x.levelno == logging.WARNING
        ]
        if messages:
            pytest.fail(f"warning messages encountered during testing: {messages}")

Полный API доступен по адресу pytest.LogCaptureFixture.

Предупреждение

Фикстура caplog добавляет обработчик в корневой регистратор для перехвата журналов. Если корневой регистратор изменяется во время теста, например с помощью logging.config.dictConfig, этот обработчик может быть удалён, из-за чего журналы не будут перехватываться. Чтобы этого избежать, убедитесь, что конфигурация корневого регистратора только добавляет обработчики к уже существующим.

Журналы в реальном времени

Если задать для параметра конфигурации log_cli значение true, pytest будет выводить записи журнала прямо в консоль по мере их создания.

Уровень журнала, начиная с которого записи будут выводиться в консоль, можно задать с помощью --log-cli-level. Этот параметр принимает имена уровней журнала или числовые значения, приведённые в документации по logging.

Кроме того, можно указать --log-cli-format и --log-cli-date-format. По умолчанию они совпадают с --log-format и --log-date-format, если не заданы, но применяются только к обработчику журналирования консоли.

Все параметры CLI для журналирования также можно задать в файле конфигурации. Имена параметров:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

Если нужно записать в файл все вызовы журналирования всего набора тестов, передайте --log-file=/path/to/log/file. По умолчанию файл журнала открывается в режиме записи, то есть при каждом сеансе тестирования его содержимое перезаписывается. Если файл нужно открывать в режиме добавления, передайте --log-file-mode=a. Обратите внимание: относительные пути к файлу журнала, переданные через CLI или указанные в файле конфигурации, всегда разрешаются относительно текущего рабочего каталога.

Уровень журнала для файла также можно задать с помощью --log-file-level. Этот параметр принимает имена уровней журнала или числовые значения, приведённые в документации по logging.

Кроме того, можно указать --log-file-format и --log-file-date-format. Они соответствуют --log-format и --log-date-format, но применяются к обработчику журналирования файла.

Все параметры файла журнала также можно задать в файле конфигурации. Имена параметров:

  • log_file
  • log_file_mode
  • log_file_level
  • log_file_format
  • log_file_date_format

Можно вызвать set_log_path(), чтобы динамически настроить путь log_file. Эта возможность считается экспериментальной. Обратите внимание: set_log_path() учитывает параметр log_file_mode.

Настройка цветов

Уровни журнала выделяются цветом, если включён цветной вывод в терминал. Изменить цвета по умолчанию или задать цвет для пользовательских уровней журнала можно с помощью add_color_level(). Пример:

@pytest.hookimpl(trylast=True)
def pytest_configure(config):
    logging_plugin = config.pluginmanager.get_plugin("logging-plugin")

    # Change color on existing log level
    logging_plugin.log_cli_handler.formatter.add_color_level(logging.INFO, "cyan")

    # Add color to a custom log level (a custom log level `SPAM` is already set up)
    logging_plugin.log_cli_handler.formatter.add_color_level(logging.SPAM, "blue")

Предупреждение

Эта возможность и её API считаются экспериментальными и могут изменяться между выпусками без уведомления об устаревании.

Примечания к выпуску

Эта возможность была представлена как полноценная замена плагину pytest-catchlog; они несовместимы друг с другом. При появлении этой возможности API обратной совместимости с pytest-capturelog был удалён. Поэтому, если по этой причине вам всё ещё нужен pytest-catchlog, можно отключить встроенную возможность, добавив в файл конфигурации:

toml

[pytest]
addopts = ["-p", "no:logging"]

ini

[pytest]
addopts = -p no:logging

Несовместимые изменения в pytest 3.4

Эта возможность появилась в 3.3, и после отзывов сообщества в 3.4 были внесены некоторые несовместимые изменения:

  • Уровни журнала больше не изменяются, если это явно не запрошено параметром конфигурации log_level или параметром командной строки --log-level. Это позволяет пользователям самостоятельно настраивать объекты регистраторов. Параметр log_level задаёт глобальный уровень перехвата, поэтому, если конкретному тесту требуется уровень ниже указанного, используйте возможность caplog.set_level(), иначе этот тест может завершиться с ошибкой.
  • Журналы в реальном времени теперь по умолчанию отключены. Их можно включить, задав для параметра конфигурации log_cli значение true. При включении повышается подробность вывода, чтобы журналирование каждого теста было видно.
  • Журналы в реальном времени теперь выводятся в sys.stdout, и для этого больше не требуется параметр командной строки -s.

Чтобы частично восстановить поведение журналирования версии 3.3, добавьте в файл конфигурации следующие параметры:

toml

[pytest]
log_cli = true
log_level = "NOTSET"

ini

[pytest]
log_cli = true
log_level = NOTSET

Подробнее об обсуждении, приведшем к этим изменениям, можно узнать в #3013.

© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/how-to/logging.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API