34

我想确保我的代码中的某个条件导致将日志消息写入 django 日志。我将如何使用 Django 单元测试框架来做到这一点?

有没有一个地方可以让我检查记录的消息,就像我可以检查已发送的电子邮件一样?我的单元测试扩展了django.test.TestCase.

4

5 回答 5

44

使用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")
于 2013-02-04T16:07:36.250 回答
33

您也可以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
    )

这使您可以避免只为日志打补丁。

于 2017-11-03T08:58:41.520 回答
8

模拟 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

于 2016-01-27T12:29:18.733 回答
6

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 支持)

于 2019-01-05T18:38:22.087 回答
0

如果您正在使用测试类,则可以使用以下解决方案:

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

于 2016-10-23T17:42:46.727 回答