【发布时间】:2019-09-01 16:53:49
【问题描述】:
我正在寻找一种优雅且 Pythonic 的解决方案,以使测试将日志保存到文件中,但 仅 以防测试失败。我想保持简单,并坚持使用 Python 的内置 logging 模块。
我目前的解决方案是对每个测试的断言使用包装函数:
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
)
虽然它按我的预期工作,但对我来说,这个解决方案似乎很笨拙而且不太Pythonic。
- 什么是(有)更优雅的方式来实现相同的结果?
- 当前方法的缺点是什么?
【问题讨论】:
-
我看不到任何方法可以覆盖所有各种断言方法的行为,因此包装函数可能是最好的方法。也就是说:(1)您应该将 basicConfig 完全移出该模块(如果已经配置了根记录器,它甚至不会做任何事情)并将 getLogger 调用移至模块级别; (2) 您不需要捕获当前时间,因为调试调用已经产生了(
asctime字段); (3) 我认为不需要重复 expected_response 和 actual_response - 这只会让每次调用assertWithLogging更加冗长。 -
@JoeP,感谢您的评论。我有一些后续问题:(1) 您是否打算将
basicConfig移至单独的模块(显然与import logging一起),然后将此模块导入需要记录器的任何地方? (2) 我使用当前时间,使其成为日志文件名的一部分。是否可以将asctime用作basicConfig(filename=...)的一部分? (3) 您是否建议记录断言消息?因为现在,如果我删除expected_response和actual_response的日志记录,则只保留someTest has failed。
标签: python python-3.x python-2.7 unit-testing logging