Модуль pytest
автоматически фиксирует сообщения уровня WARNING и выше c отображением их в отдельном разделе для каждого неудавшегося теста так же, как захваченные stdout
и stderr
.
По умолчанию, каждое захваченное сообщение журнала выводит название тестового модуля, номер строки, уровень логирования и сообщение.
При желании, можно указать pytest
формат ведения журнала и даты для всего, что поддерживает модуль logging
, передав определенные параметры форматирования в CLI:
pytest --log-format="%(asctime)s %(levelname)s %(message)s" \ --log-date-format="%Y-%m-%d %H:%M:%S"
Эти параметры также можно настроить с помощью файла pytest.ini
:
[pytest] log_format = %(asctime)s %(levelname)s %(message)s log_date_format = %Y-%m-%d %H:%M:%S
Кроме того, при неудачных тестах можно полностью отключить отчеты о захваченном содержимом (stdout
, stderr
и log
) с помощью:
pytest --show-capture=no
caplog
.Внутри тестов можно изменить уровень логирования для захваченных сообщений журнала. Такое поведение поддерживается встроенной фикстурой caplog
:
def test_foo(caplog): caplog.set_level(logging.INFO) pass
По умолчанию, уровень логирования устанавливается для корневого регистратора, однако для удобства можно установить уровень журнала для любого регистратора:
def test_foo(caplog): caplog.set_level(logging.CRITICAL, logger="root.baz") pass
Установленные уровни журналов восстанавливаются автоматически по окончании теста. Также можно использовать диспетчер контекста для временного изменения уровня журнала внутри блока 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
.
Также можно прибегнуть к caplog.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
содержит записи только текущего этапа тестирования, поэтому фазы настройки тестов будут содержать только эти журналы, то же самое с фазами вызова 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}" )
pytest
.Для того, чтобы фреймворк pytest
выводил записи журнала в том виде, в каком они выводятся непосредственно в консоль, для параметра конфигурации log_cli
необходимо установить значение true
.
# pytest.ini [pytest] log_cli=true
Можно указать уровень ведения логов, для которого записи журнала с равным или более высоким уровнем выводятся на консоль, передав опцию CLI --log-cli-level
. Этот параметр принимает имена уровней ведения журнала, или целое число в качестве номера уровня логов.
Кроме того, можно указывать опции CLI --log-cli-format
и --log-cli-date-format
, которые отражают и по умолчанию --log-format
и --log-date-format
, если они не указаны, но применяются только к обработчику протоколирования консоли.
Все параметры CLI ведения логов можно установить в INI-файле конфигурации:
log_cli_level
: устанавливает минимальный уровень сообщений журнала, которые должны быть захвачены для ведения журнала в реальном времени. Можно использовать целочисленное значение или имена уровней.
[pytest] log_cli_level = INFO
log_cli_format
: задает совместимую с модулем logging
строку журнала, используемую для форматирования сообщений ведения журнала в реальном времени.
[pytest] log_cli_level = %(asctime)s %(levelname)s %(message)s
log_cli_date_format
: задает строку, совместимую с time.strftime()
, которая будет использоваться при форматировании дат для записи в реальном времени.
[pytest] log_cli_level = %Y-%m-%d %H:%M:%S
Если нужно записать все вызовы журнала тестов в файл, то можно передать опцию CLI --log-file=/path/to/log/file
. Этот файл журнала открывается в режиме записи, и он будет перезаписываться при каждом сеансе выполнения тестов. Обратите внимание, что относительные пути для расположения файла журнала, независимо от того, переданы ли они через интерфейс командной строки или объявлены в файле конфигурации, всегда разрешаются относительно текущего рабочего каталога.
Для файла журнала можно указать уровень логирования, передав опцию --log-file-level
. Этот параметр принимает имена уровней ведения журнала (т. е. имена уровней в верхнем регистре), или целое число в качестве номера уровня.
Кроме того, можно указать --log-file-format
и --log-file-date-format
, которые эквивалентны --log-format
и --log-date-format
, но применяются к обработчику регистрации файла журнала.
Все параметры файла журнала также можно установить в INI-файле конфигурации:
log_file
: задает имя файла относительно текущего рабочего каталога, в который должны записываться сообщения журнала, в дополнение к другим активным средствам ведения журнала.
[pytest] log_file = logs/pytest-logs.txt
log_file_level
: устанавливает минимальный уровень сообщения, который должен быть захвачен для файла журнала. Можно использовать целочисленное значение или имена уровней.
[pytest] log_file_level = INFO
log_file_format
: задает строку, совместимую с модулем logging
, используемую для форматирования сообщений, перенаправляемых в файл журнала.
[pytest] log_file_format = %(asctime)s %(levelname)s %(message)s
log_file_date_format
: задает строку, совместимую с time.strftime()
, которая будет использоваться при форматировании дат для файла журнала.
[pytest] log_file_date_format = %Y-%m-%d %H:%M:%S
Можно вызвать set_log_path()
для динамической настройки пути log_file
. Эта функция считается экспериментальной.
LogCaptureFixture
.Класс LogCaptureFixture
обеспечивает доступ и управление записью журнала и имеет следующие свойства и методы:
LogCaptureFixture.handler
:Свойство LogCaptureFixture.handler
получает обработчик ведения журнала, используемый фикстурой. Возвращаемый тип LogCaptureHandler
.
LogCaptureFixture.get_records(when)
:Метод LogCaptureFixture.get_records()
получает записи журнала для одного из возможных этапов тестирования..
Аргумент when
- это строка с фазой тестирования. Допустимыми значениями являются: 'setup'
, 'call'
and 'teardown'
. Возвращает список захваченных записей на данном этапе (List[logging.LogRecord]
)
LogCaptureFixture.text
:Свойство LogCaptureFixture.text
возвращает отформатированный текст журнала.
LogCaptureFixture.records
:Свойство LogCaptureFixture.records
возвращает список записей журнала.
LogCaptureFixture.record_tuples
:Свойство LogCaptureFixture.record_tuples
возвращает список урезанной версии записей журнала, предназначенных для использования при сравнении утверждений.
Формат кортежа: (logger_name, log_level, message)
.
LogCaptureFixture.messages
:Свойство LogCaptureFixture.messages
возвращает список сообщений журнала с интерполяцией формата.
В отличие от LogCaptureFixture.records
, которые содержат строку формата и параметры для интерполяции, все сообщения журнала в этом списке интерполируются.
В отличие от LogCaptureFixture.text
, который содержит выходные данные обработчика, сообщения журнала в этом списке не содержат уровни, отметки времени и т. д., что делает точное сравнение более надежным.
_Обратите внимание), что информация о трассировке или стеке (от logging.exception()
или аргументов exc_info
или stack_info
к функциям ведения журнала) не включается, так как она добавляется средством форматирования в обработчик.
LogCaptureFixture.clear()
:Метод LogCaptureFixture.clear()
сбрасывает список записей журнала и записанный текст журнала.
LogCaptureFixture.set_level(level, logger=None)
:Метод LogCaptureFixture.set_level()
устанавливает уровень регистратора на время теста.
level
- целое число, которое указывает уровень логирования.logger
- строка, представляющая собой регистратор для обновления. Если не указан, то по умолчанию - корневой регистратор.LogCaptureFixture.at_level(level, logger=None)
:Метод LogCaptureFixture.at_level()
представляет собой контекстный менеджер, который задает уровень для сбора журналов. После завершения инструкции with
уровень восстанавливается до своего первоначального значения.
level
- целое число, которое указывает уровень логирования.logger
- строка, представляющая собой регистратор для обновления. Если не указан, то по умолчанию - корневой регистратор.