最近,我正在编写一个python日志记录扩展程序,我想为该扩展程序添加一些测试,以验证我的扩展程序是否按预期工作。
但是,我不知道如何捕获完整的日志并与unittest / pytest中的例外结果进行比较。
简化样本:
# app.py
import logging
def create_logger():
formatter = logging.Formatter(fmt='%(name)s-%(levelname)s-%(message)s')
hdlr = logging.StreamHandler()
hdlr.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.setLevel('DEBUG')
logger.addHandler(hdlr)
return logger
app_logger = create_logger()
这是我的测试
尝试1:单元测试
from app import app_logger
import unittest
class TestApp(unittest.TestCase):
def test_logger(self):
with self.assertLogs('', 'DEBUG') as cm:
app_logger.debug('hello')
# or some other way to capture the log output.
self.assertEqual('app-DEBUG-hello', cm.output)
cm.output = 'app-DEBUG-hello'
cm.output = ['DEBUG:app:hello']
尝试2:pytest Caplog
from app import app_logger
import pytest
def test_logger(caplog):
app_logger.debug('hello')
assert caplog.text == 'app-DEBUG-hello'
caplog.text = 'app-DEBUG-hello'
caplog.text = 'test_logger.py 6 DEBUG hello'
尝试3:pytest capsys
从应用程序导入app_logger 导入pytest
def test_logger(capsys):
app_logger.debug('hello')
out, err = capsys.readouterr()
assert err
assert err == 'app-DEBUG-hello'
err = 'app-DEBUG-hello'
err = ''
考虑到会有许多格式不同的测试,我不想手动检查日志格式。我不知道如何获取控制台上看到的完整日志,并将其与测试用例中的预期日志进行比较。希望您的帮助,谢谢。
答案 0 :(得分:1)
我知道这很旧,但是在这里发布,因为它在Google中为我拉起了...
可能需要清理,但这对我来说已经很近了,所以我认为分享是一件好事。
这是我组合在一起的一个测试用例,可以让我通过复制格式化程序来验证特定的处理程序是否按预期进行了格式化:
import io
import logging
from django.conf import settings
from django.test import SimpleTestCase
from django.utils.log import DEFAULT_LOGGING
class SetupLoggingMixin:
def setUp(self):
super().setUp()
logging.config.dictConfig(settings.LOGGING)
self.stream = io.StringIO()
self.root_logger = logging.getLogger("")
self.root_hdlr = logging.StreamHandler(self.stream)
console_handler = None
for handler in self.root_logger.handlers:
if handler.name == 'console':
console_handler = handler
break
if console_handler is None:
raise RuntimeError('could not find console handler')
formatter = console_handler.formatter
self.root_formatter = formatter
self.root_hdlr.setFormatter(self.root_formatter)
self.root_logger.addHandler(self.root_hdlr)
def tearDown(self):
super().tearDown()
self.stream.close()
logging.config.dictConfig(DEFAULT_LOGGING)
这是使用方法的示例:
class SimpleLogTests(SetupLoggingMixin, SimpleTestCase):
def test_logged_time(self):
msg = 'foo'
self.root_logger.error(msg)
self.assertEqual(self.stream.getvalue(), 'my-expected-message-formatted-as-expected')
答案 1 :(得分:0)
在阅读unittest
库的源代码之后,我制定了以下绕过方法。请注意,它可以通过更改导入模块的受保护成员来工作,因此将来的版本中可能会破坏它。
from unittest.case import _AssertLogsContext
_AssertLogsContext.LOGGING_FORMAT = 'same format as your logger'
执行这些命令后,self.assertLogs
打开的日志上下文将使用上述格式。我真的不知道为什么将这些值保留为硬编码且不可配置。
我没有找到读取记录器格式的选项,但是如果您使用logging.config.dictConfig
,则可以使用同一词典中的值。
答案 2 :(得分:0)
我知道这并不能完全回答OP的问题,但是我在寻找一种捕获日志消息的巧妙方法时偶然发现了这篇文章。
采用@ user319862的功能,我已经对其进行了清理和简化。
import unittest
import logging
from io import StringIO
class SetupLogging(unittest.TestCase):
def setUp(self):
super().setUp()
self.stream = StringIO()
self.root_logger = logging.getLogger("")
self.root_hdlr = logging.StreamHandler(self.stream)
self.root_logger.addHandler(self.root_hdlr)
def tearDown(self):
super().tearDown()
self.stream.close()
def test_log_output(self):
""" Does the logger produce the correct output? """
msg = 'foo'
self.root_logger.error(msg)
self.assertEqual(self.stream.getvalue(), 'foo\n')
if __name__ == '__main__':
unittest.main()
答案 3 :(得分:0)
我是 Python 新手,但在其他语言的测试/tdd 方面有一些经验,发现“更改”格式化程序的默认方式是添加新的流处理程序,但如果您已经在记录器中定义了流(即使用 Azure 函数或 TestCase::assertLogs
为您添加一个)您最终会记录两次,一次使用您的格式,另一次使用“默认”格式。
如果在 OP 中,函数 create_logger
改变了当前 StreamHandler
的格式化程序,而不是添加一个新的 StreamHandler
(检查是否存在,如果不创建一个新的和所有那个爵士乐...)
然后您可以在 create_logger
之后调用 with self.assertLogs('', 'DEBUG') as cm:
并断言 cm.output
并且它只是有效,因为您正在改变 Formatter
的 StreamHandler
assertLogs
正在添加。
所以基本上发生的事情是执行顺序不适合测试。
OP中的执行顺序是:
应该什么时候 执行顺序为: