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

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

logging.basicConfig(level=logging.DEBUG)

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

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

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


当前回答

我喜欢Hassek的自定义测试运行器的想法。值得注意的是,Django testsuiterunner不再是Django 1.6+中的默认测试运行器,它已经被DiscoverRunner所取代。对于默认行为,测试运行器应该更像:

import logging

from django.test.runner import DiscoverRunner

class NoLoggingTestRunner(DiscoverRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):

        # disable logging below CRITICAL while testing
        logging.disable(logging.CRITICAL)

        return super(NoLoggingTestRunner, self).run_tests(test_labels, extra_tests, **kwargs)

其他回答

如果你正在使用pytest:

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

LOGGING_CONFIG = None

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

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

测试将使用pytest设置的日志运行。它可以在pytest设置中根据您的喜好进行配置(例如,tox.ini)。要包含调试级别的日志消息,请使用log_level = 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)

如果你正在使用pytest,你可以安装超级有用的pytest-mock插件,并定义一个自动使用的会话范围的fixture,可以由env var触发:

# conftest.py

import os
import pytest


@pytest.fixture(autouse=True, scope="session")
def _shut_logger(session_mocker):
    if os.getenv("SHUT_LOGGER", None):
        return session_mocker.patch("foo.logger")

我喜欢Hassek的自定义测试运行器的想法。值得注意的是,Django testsuiterunner不再是Django 1.6+中的默认测试运行器,它已经被DiscoverRunner所取代。对于默认行为,测试运行器应该更像:

import logging

from django.test.runner import DiscoverRunner

class NoLoggingTestRunner(DiscoverRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):

        # disable logging below CRITICAL while testing
        logging.disable(logging.CRITICAL)

        return super(NoLoggingTestRunner, self).run_tests(test_labels, extra_tests, **kwargs)

如果你有不同的初始化器模块用于测试,开发和生产,那么你可以禁用任何东西或重定向初始化器。我有local。py, test。py和production。py,它们都继承自common。y

py执行所有主要配置,包括以下代码段:

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'django.server': {
        '()': 'django.utils.log.ServerFormatter',
        'format': '[%(server_time)s] %(message)s',
    },
    'verbose': {
        'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
    },
    'simple': {
        'format': '%(levelname)s %(message)s'
    },
},
'filters': {
    'require_debug_true': {
        '()': 'django.utils.log.RequireDebugTrue',
    },
},
'handlers': {
    'django.server': {
        'level': 'INFO',
        'class': 'logging.StreamHandler',
        'formatter': 'django.server',
    },
    'console': {
        'level': 'DEBUG',
        'class': 'logging.StreamHandler',
        'formatter': 'simple'
    },
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
'loggers': {
    'django': {
        'handlers': ['console'],
        'level': 'INFO',
        'propagate': True,
    },
    'celery.tasks': {
        'handlers': ['console'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'django.server': {
        'handlers': ['django.server'],
        'level': 'INFO',
        'propagate': False,
    },
}

然后在test.py中,我有这个:

console_logger = Common.LOGGING.get('handlers').get('console')
console_logger['class'] = 'logging.FileHandler
console_logger['filename'] = './unitest.log

这将控制台处理程序替换为FileHandler,这意味着仍然可以获得日志记录,但我不必触及生产代码库。