我正在使用一个简单的基于单元测试的测试运行器来测试我的Django应用程序。

我的应用程序本身被配置为在settings.py中使用一个基本的日志记录器:

logging.basicConfig(level=logging.DEBUG)

并在我的应用程序代码使用:

logger = logging.getLogger(__name__)
logger.setLevel(getattr(settings, 'LOG_LEVEL', logging.DEBUG))

但是,在运行单元测试时,我想禁用日志记录,这样它就不会使测试结果输出混乱。有没有一种简单的方法以全局方式关闭日志记录,这样当我运行测试时,特定于应用程序的日志记录器就不会把东西写到控制台了?


当前回答

我发现,对于在unittest或类似框架中的测试,在单元测试中安全禁用不必要的日志记录的最有效方法是在特定测试用例的setUp/tearDown方法中启用/禁用。这样就可以明确地锁定应该禁用日志的位置。您也可以在测试类的记录器上显式地执行此操作。

import unittest
import logging

class TestMyUnitTest(unittest.TestCase):
    def setUp(self):
        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

其他回答

logging.disable(logging.CRITICAL)

将禁用级别小于或等于CRITICAL的所有日志调用。可以重新启用日志记录

logging.disable(logging.NOTSET)

有没有一种简单的方法以全局方式关闭日志记录,这样当我运行测试时,特定于应用程序的日志记录器就不会把东西写到控制台了?

其他答案通过全局设置日志基础设施以忽略任何内容来防止“将内容写入控制台”。这是可行的,但我觉得这种方法太生硬了。我的方法是执行配置更改,只做防止日志泄漏到控制台上所需的事情。所以我在settings.py中添加了一个自定义日志过滤器:

from logging import Filter

class NotInTestingFilter(Filter):

    def filter(self, record):
        # Although I normally just put this class in the settings.py
        # file, I have my reasons to load settings here. In many
        # cases, you could skip the import and just read the setting
        # from the local symbol space.
        from django.conf import settings

        # TESTING_MODE is some settings variable that tells my code
        # whether the code is running in a testing environment or
        # not. Any test runner I use will load the Django code in a
        # way that makes it True.
        return not settings.TESTING_MODE

我配置Django日志使用过滤器:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'testing': {
            '()': NotInTestingFilter
        }
    },
    'formatters': {
        'verbose': {
            'format': ('%(levelname)s %(asctime)s %(module)s '
                       '%(process)d %(thread)d %(message)s')
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'filters': ['testing'],
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'foo': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

最终结果是:当我在测试时,没有任何内容进入控制台,但其他内容保持不变。

为什么这么做?

我设计了包含日志记录指令的代码,这些指令仅在特定情况下触发,并且在出现问题时输出诊断所需的准确数据。因此,我测试了它们应该做什么,因此完全禁用日志记录对我来说是不可行的。我不想在软件投入生产后发现我认为应该记录的内容没有被记录。

此外,一些测试运行程序(例如Nose)将在测试期间捕获日志,并将日志的相关部分与测试失败一起输出。它有助于找出测试失败的原因。如果日志记录完全关闭,那么就无法捕获任何东西。

如果你正在使用pytest:

由于pytest捕获日志消息,并且仅在失败的测试中显示它们,因此通常不希望禁用任何日志记录。相反,使用一个单独的settings.py文件进行测试(例如test_settings.py),并添加到它:

LOGGING_CONFIG = None

这告诉Django完全跳过日志配置。LOGGING设置将被忽略,并可以从设置中删除。

使用这种方法,您不会获得通过测试的任何日志记录,而会获得失败测试的所有可用日志记录。

测试将使用pytest设置的日志运行。它可以在pytest设置中根据您的喜好进行配置(例如,tox.ini)。要包含调试级别的日志消息,请使用log_level = debug(或相应的命令行参数)。

b.h.

对我来说,在conftest.py:

 import confing
 # disable logging for tests
 [logging.disable(level) for level in [logging.DEBUG,
                                       logging.INFO,
                                       logging.ERROR,
                                       logging.CRITICAL]]

我使用了一个简单的方法装饰器来禁用特定测试方法中的日志记录。

def disable_logging(f):

    def wrapper(*args):
        logging.disable(logging.CRITICAL)
        result = f(*args)
        logging.disable(logging.NOTSET)

        return result

    return wrapper

然后我在下面的例子中使用它:

class ScenarioTestCase(TestCase):

    @disable_logging
    test_scenario(self):
        pass