#python #python-3.x #python-2.7 #unit-testing #logging
#python #python-3.x #python-2.7 #модульное тестирование #ведение журнала
Вопрос:
Я ищу элегантное и питоновское решение, чтобы тесты сохраняли журнал в файл, но только в случае сбоя теста. Я хотел бы упростить задачу и придерживаться встроенного logging
модуля Python.
Мое текущее решение — использовать функцию-оболочку для утверждения каждого теста:
import unittest
class superTestCase(unittest.TestCase):
...
def assertWithLogging(self, assertion, assertion_arguments, expected_response, actual_response, *args):
try:
assertion(*assertion_arguments)
except AssertionError as ae:
test_name = inspect.stack()[1][3]
current_date_time = datetime.datetime.now().strftime("%Y.%m.%d %H-%M-%S")
logging.basicConfig(filename='tests/{}-{}-Failure.log'.format(current_date_time, test_name),
filemode='a',
format='%(message)s',
level=logging.DEBUG
)
logger = logging.getLogger('FailureLogger')
logger.debug('{} has failed'.format(test_name))
logger.debug('Expected response(s):')
logger.debug(expected_response)
logger.debug('Actual response:')
logger.debug(actual_response)
for arg in args:
logger.debug('Additionl logging info:')
logger.debug(arg)
raise ae
def testSomething(self):
...
self.assertWithLogging(self.assertEqual,
[expected_response, actual_response]
expected_response,
actual_response,
some_other_variable
)
Хотя это работает так, как я ожидаю, это решение кажется мне неуклюжим и не слишком питоническим.
- Какой был бы (есть) более элегантный способ добиться того же результата?
- Каковы недостатки текущего подхода?
Комментарии:
1. Я не вижу никакого способа переопределить поведение всех различных методов assert, поэтому функция-оболочка может быть лучшим способом. Тем не менее: (1) Вы должны полностью удалить basicConfig из этого модуля (он даже ничего не сделает, если корневой регистратор уже настроен) и переместить вызов getLogger на уровень модуля; (2) Вам не нужно фиксировать текущее время, поскольку вызовы debug уже производят это (
asctime
поле); (3) Я не вижу необходимости повторять expected_response и actual_response — это просто делает каждый вызовassertWithLogging
более подробным.2. @JoeP, спасибо за комментарий. У меня есть несколько последующих вопросов: (1) Вы хотите перейти
basicConfig
к отдельному модулю (вместе сimport logging
, очевидно), а затем импортировать этот модуль туда, где требуется logger? (2) Я использую текущее время, чтобы сделать его частью имени файла журнала. Можно ли использоватьasctime
как частьbasicConfig(filename=...)
? (3) Предлагаете ли вы вместо этого регистрировать сообщение об утверждении? Потому что теперь, если я удалю ведениеexpected_response
журнала иactual_response
,someTest has failed
останется только.
Ответ №1:
Вы можете использовать различные механизмы ведения журнала, в которых вы можете установить тип журналов, которые вы хотите получить.
В приведенном ниже журнале будут регистрироваться только сообщения об ошибках.
Logger.error(msg, *args, **kwargs)
Это регистрируется msg
с уровнем logging.ERROR
в этом регистраторе. Аргументы интерпретируются как for debug()
.
Комментарии:
1. Спасибо за ваш ответ. Я, вероятно, был недостаточно точен в том, о чем спрашивал. Я ищу способ регистрировать некоторые сообщения (фактически сохранять журнал в файл, что в данном случае можно считать эквивалентным), только если утверждение теста завершается неудачно (независимо от сообщения
logging.level
). Поскольку я не могу добавлятьlogger
вызовы внутри самого утверждения, я придумал решение-оболочку, представленное в вопросе. Хотя я чувствую, что это неуклюже, поэтому я ищу лучшую альтернативу. Надеюсь, теперь вопрос имеет больше смысла.