Как управлять журналированием
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-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, но применяются к обработчику журналирования файла.
Все параметры файла журнала также можно задать в файле конфигурации. Имена параметров:
Можно вызвать 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