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

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

logging.basicConfig(level=logging.DEBUG)

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

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

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


当前回答

在我希望暂时抑制特定记录器的情况下,我写了一个我发现有用的小上下文管理器:

from contextlib import contextmanager
import logging

@contextmanager
def disable_logger(name):
    """Temporarily disable a specific logger."""
    logger = logging.getLogger(name)
    old_value = logger.disabled
    logger.disabled = True
    try:
        yield
    finally:
        logger.disabled = old_value

然后你可以这样使用它:

class MyTestCase(TestCase):
    def test_something(self):
        with disable_logger('<logger name>'):
            # code that causes the logger to fire

这样做的好处是,一旦with操作完成,记录器将被重新启用(或设置回其先前的状态)。

其他回答

我喜欢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)

有时你想要日志,有时不想要。我在settings。py中有这段代码

import sys

if '--no-logs' in sys.argv:
    print('> Disabling logging levels of CRITICAL and below.')
    sys.argv.remove('--no-logs')
    logging.disable(logging.CRITICAL)

所以如果你使用——no-logs选项运行测试,你将只得到关键日志:

$ python ./manage.py tests --no-logs
> Disabling logging levels of CRITICAL and below.

如果您想加快持续集成流的测试,这是非常有用的。

如果你正在使用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")

我发现,对于在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)

如果你不想在setUp()和tearDown()中反复为unittest打开/关闭它(不知道原因),你可以在每个类中只做一次:

    import unittest
    import logging

    class TestMyUnitTest(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            logging.disable(logging.CRITICAL)
        @classmethod
        def tearDownClass(cls):
            logging.disable(logging.NOTSET)