Ведение журнала в тестах pytest

90

Я хотел бы поместить несколько операторов регистрации в тестовую функцию, чтобы проверить некоторые переменные состояния.

У меня есть следующий фрагмент кода:

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 ')

Получаю следующий результат:

[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 

Обратите внимание, что '__name__ == __main__'на консоль передаются только сообщения журнала из блока.

Есть ли способ принудительно pytestвывести журнал на консоль из методов тестирования?

суперселектор
источник
3
Вы можете взглянуть на этот ответ , опубликованный создателем py.test. Он предлагает плагин pytest, который обеспечивает высокую степень универсальности.
chb 02

Ответы:

30

У меня работает, вот результат, который я получаю: [snip -> пример неверен]

Изменить: кажется, вам нужно передать -sпараметр py.test, чтобы он не захватил stdout. Здесь (py.test не установлен) достаточно было использовать python pytest.py -s pyt.py.

Для вашего кода, все , что вам нужно пройти -sв argsк main:

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

См. Документацию py.test о захвате вывода .

TryPyPy
источник
Сожалею. Я вставил код в спешке. Удалите «assert 0 == 1» из функции «test_one», чтобы заметить «проблему». Только в случае сбоя (который я вынудил из-за ложного утверждения) py.test, похоже, печатает информацию о журнале.
superselector
Нет проблем, я узнал, как исправить в командной строке, ищу программный способ.
TryPyPy
1
вы также можете перенаправить вывод журнала в какой-либо файл вместо неявного stderr по умолчанию.
hpk42
@superselector hpk42 - самый крутой парень, слушайте. IIUC, в вашем коде это будет logging.basicConfig(filename="somelog.txt", level=logging.DEBUG).
TryPyPy
115

Начиная с версии 3.3, pytestподдерживается ведение журнала в реальном времени, что означает, что все записи журнала, созданные в ходе тестов, будут немедленно распечатаны на терминале. Эта функция задокументирована в разделе Live Logs . Живое ведение журнала по умолчанию отключено; чтобы включить его, установите log_cli = 1в pytest.iniконфиге 1 . Живое ведение журнала поддерживает отправку в терминал и в файл; соответствующие параметры позволяют настраивать записи:

Терминал:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

файл:

  • log_file
  • log_file_level
  • log_file_format
  • log_file_date_format

Примечание : log_cliфлаг не может быть передан из командной строки и должен быть установлен pytest.ini. Все остальные параметры могут быть переданы из командной строки или установлены в файле конфигурации. Как указал Кевин Барре в этом комментарии , переопределение параметров ini из командной строки можно выполнить с помощью -o/--overrideпараметра. Поэтому вместо объявления log_cliin pytest.iniвы можете просто позвонить:

$ pytest -o log_cli=true ...

Примеры

Простой тестовый файл, используемый для демонстрации:

# 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

Как видите, никаких дополнительных настроек не требуется; pytestавтоматически настроит регистратор на основе параметров, указанных в pytest.iniкомандной строке или переданных из нее.

Живая запись на терминал, INFOуровень, необычный вывод

Конфигурация в 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

Запуск теста:

$ 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 =============================

Живая запись в терминал и файл, только сообщение и CRITICALуровень в терминале, необычный вывод в pytest.logфайл

Конфигурация в 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

Тестовый забег:

$ 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 Хотя можно настроить pytestв setup.cfgсоответствии с [tool:pytest]раздела, не поддавайтесь искушению сделать это , если вы хотите обеспечить собственный формат живого журнала. Другие инструменты чтения setup.cfgмогут рассматривать такие вещи как %(message)sинтерполяцию строк и завершаться ошибкой. Используйте, pytest.iniчтобы избежать ошибок.

хрип
источник
17
Что касается примечания, которое log_cliдолжно быть в pytest.ini , кажется, вы можете использовать -oпараметр для переопределения значения из командной строки. pytest -o log_cli=true --log-cli-level=DEBUGработает для меня.
Кевин Барре
@ KévinBarré очень хороший комментарий и очень полезный совет в целом, спасибо! Обновил ответ.
hoefling 02
Это определенно правильный ответ при использовании журналирования. Хотя мне нравится различать журналы, которые находятся внутри тестов, и журналы, которые находятся внутри тестируемой системы, которые следует рассматривать отдельно.
CMCDragonkai
@CMCDragonkai, к сожалению, pytestнесколько ограничен в этом вопросе. Однако это должно быть выполнено с помощью специальной конфигурации ведения журнала для тестов в вашем приложении; отключите распространение в ваших регистраторах и добавьте «тестовый обработчик», который ведет журнал в указанный файл. Таким образом, pytestрегистрируются только записи, поступающие из тестов, а пользовательский обработчик заботится о журналах SuT.
hoefling
1
@OfekAgmon, если вы хотите сохранить pytestвывод, вы можете использовать --result-logаргумент (хотя обратите внимание, что он устарел, вот альтернативы ). Однако вы не можете хранить pytestвыходные данные и выходные данные журнала в одном файле.
Hoefling