你怎么能用 Python 编写一个单元测试来测试记录器的输出是否确实是你期望的格式(即通过调用 logging.basicConfig() 来设置)?我正在考虑自定义 StreamHandler 和使用“re”库,但看起来传递给 StreamHandler.emit() 的 LogRecord 不能给我将输出的字符串。
2 回答
从文档(http://packages.python.org/testfixtures/logging.html):
为了解决这个问题,TestFixtures 允许您轻松捕获对 Python 日志框架的调用输出,并确保它们符合预期。根据您编写的测试类型,共有三种不同的技术。
示例包含在文档中。缩短版如下。
上下文管理器
>>> import logging
>>> from testfixtures import LogCapture
>>> with LogCapture() as l:
... logger = logging.getLogger()
... logger.info('a message')
... logger.error('an error')
之后,您可以检查日志是否相等:
>>> l.check(
... ('root', 'INFO', 'a message'),
... ('root', 'ERROR', 'another error'),
... )
Traceback (most recent call last):
...
AssertionError: Sequence not as expected:
same:
(('root', 'INFO', 'a message'),)
first:
(('root', 'ERROR', 'another error'),)
second:
(('root', 'ERROR', 'an error'),)
装饰师
与上一个类似,但适用于特定功能:
from testfixtures import log_capture
@log_capture()
def test_function(l):
logger = logging.getLogger()
logger.info('a message')
logger.error('an error')
l.check(
('root', 'INFO', 'a message'),
('root', 'ERROR', 'an error'),
)
手动使用
>>> from testfixtures import LogCapture
>>> l = LogCapture()
之后,您还可以“检查”日志:
>>> l.check(('root', 'INFO', 'a message'))
<...>
编辑:要访问特定日志并以自定义方式分析它们,您可以迭代l.records
(其中l
只是LogCapture
's 实例)并访问它们中的每一个的一些属性(例如,msg
包含发送到记录器的消息,levelname
包含级别的代号,还有很多其他属性)。
如果您只想使用标准库,此解决方案可能会有所帮助。它基于unittest
和mock
库。
例如,如果您有script.py
以下内容。
logger = logging.getLogger(__name__)
def log_something():
logger.debug("something")
你可以为它写一个看起来像这样的测试。
import unittest
import mock
from script import log_something
@mock.patch("script.logger")
def test_function(mock_log):
log_something()
assertTrue(
"something" in mock_log.debug.call_args_list[0][0][0]
)
这是使用库中的call_args_listmock
。
[0][0][0]
最后解释一下:
这
call_args_list
是一个call
对象列表,看起来像这样[call("something")]
。所以第一个[0]
是返回第一个call
对象。第二个
[0]
返回对象的参数元组call
。它看起来像这样("something",)
。第三
[0]
返回logger
在我们的例子中给出的第一个参数。所以最后的字符串将是 only"something"
。