我想确保我的代码中的某个条件导致将日志消息写入 django 日志。我将如何使用 Django 单元测试框架来做到这一点?
有没有一个地方可以让我检查记录的消息,就像我可以检查已发送的电子邮件一样?我的单元测试扩展了django.test.TestCase
.
我想确保我的代码中的某个条件导致将日志消息写入 django 日志。我将如何使用 Django 单元测试框架来做到这一点?
有没有一个地方可以让我检查记录的消息,就像我可以检查已发送的电子邮件一样?我的单元测试扩展了django.test.TestCase
.
使用mock
模块来模拟日志模块或记录器对象。完成后,检查调用日志记录函数的参数。
例如,如果您的代码如下所示:
import logging
logger = logging.getLogger('my_logger')
logger.error("Your log message here")
它看起来像:
from unittest.mock import patch # For python 2.x use from mock import patch
@patch('this.is.my.module.logger')
def test_check_logging_message(self, mock_logger):
mock_logger.error.assert_called_with("Your log message here")
您也可以assertLogs
使用django.test.TestCase
当你的代码是
import logging
logger = logging.getLogger('my_logger')
def code_that_throws_error_log():
logger.error("Your log message here")
这是测试代码。
with self.assertLogs(logger='my_logger', level='ERROR') as cm:
code_that_throws_error_log()
self.assertIn(
"ERROR:your.module:Your log message here",
cm.output
)
这使您可以避免只为日志打补丁。
模拟 logger 对象的常用方法(请参阅出色的小伙 Simeon Visser 的回答)有点棘手,因为它需要测试来模拟它完成的所有地方的日志记录。如果日志记录来自多个模块,或者在您不拥有的代码中,这会很尴尬。如果日志记录来自的模块更改名称,它将破坏您的测试。
出色的 ' testfixtures ' 包包括添加日志处理程序的工具,该处理程序捕获所有生成的日志消息,无论它们来自何处。捕获的消息稍后可以通过测试进行询问。最简单的形式:
假设正在测试的代码,其中记录:
import logging
logger = logging.getLogger()
logger.info('a message')
logger.error('an error')
对此的测试将是:
from testfixtures import LogCapture
with LogCapture() as l:
call_code_under_test()
l.check(
('root', 'INFO', 'a message'),
('root', 'ERROR', 'an error'),
)
logging.getLogger()
“root”一词表示日志记录是通过使用(即没有参数)创建的记录器发送的。如果您将 arg 传递给 getLogger(__name__
常规),则该 arg 将用于代替“root”。
测试不关心哪个模块创建了日志记录。它可能是我们的被测代码调用的子模块,包括第 3 方代码。
测试断言所生成的实际日志消息,而不是模拟技术,后者断言所传递的参数。如果 logging.info 调用使用 '%s' 格式字符串和您不扩展自己的附加参数(例如,使用logging.info('total=%s', len(items))
而不是logging.info('total=%s' % len(items))
,您应该这样做。这不是额外的工作,并允许假设的未来日志聚合服务,例如'Sentry' 正常工作 - 他们可以看到 "total=12" 和 "total=43" 是同一日志消息的两个实例。这就是 pylint 警告后一种logging.info
调用形式的原因。)
LogCapture 包括用于日志过滤等的工具。它的父 'testfixtures' 包由另一个出色的小伙 Chris Withers 编写,包括许多其他有用的测试工具。文档在这里: http: //pythonhosted.org/testfixtures/logging.html
Django 有一个很好的上下文管理器函数,叫做patch_logger
.
from django.test.utils import patch_logger
然后在您的测试用例中:
with patch_logger('logger_name', 'error') as cm:
self.assertIn("Error message", cm)
在哪里:
logger_name
是记录器名称(duh)error
是日志级别cm
是所有日志消息的列表更多细节:
https://github.com/django/django/blob/2.1/django/test/utils.py#L638
对于 django < 2.0,它应该与 python 版本无关(只要它受 dj 支持)
如果您正在使用测试类,则可以使用以下解决方案:
import logger
from django.test import TestCase
class MyTest(TestCase):
@classmethod
def setUpClass(cls):
super(MyTest, cls).setUpClass()
cls.logging_error = logging.error
logging.error = cls._error_log
@classmethod
def tearDownClass(cls):
super(MyTest, cls).tearDownClass()
logging.error = cls.logging_error
@classmethod
def _error_log(cls, msg):
cls.logger = msg
def test_logger(self):
self.assertIn('Message', self.logger)
此方法仅出于测试目的将模块的error
功能替换为logging
您的自定义方法,并将 stdout 放入cls.logger
变量中,该变量可通过调用在每个测试用例中使用self.logger
。最后,它通过将模块中的error
功能放回原处来恢复更改。logging