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

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

logging.basicConfig(level=logging.DEBUG)

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

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

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


当前回答

使用unittest.mock.patch方法有一些漂亮而干净的方法来暂停测试中的登录。

foo.py:

import logging


logger = logging.getLogger(__name__)

def bar():
    logger.error('There is some error output here!')
    return True

tests.py:

from unittest import mock, TestCase
from foo import bar


class FooBarTestCase(TestCase):
    @mock.patch('foo.logger', mock.Mock())
    def test_bar(self):
        self.assertTrue(bar())

而python3 -m unittest测试将不会产生日志输出。

其他回答

使用unittest.mock.patch方法有一些漂亮而干净的方法来暂停测试中的登录。

foo.py:

import logging


logger = logging.getLogger(__name__)

def bar():
    logger.error('There is some error output here!')
    return True

tests.py:

from unittest import mock, TestCase
from foo import bar


class FooBarTestCase(TestCase):
    @mock.patch('foo.logger', mock.Mock())
    def test_bar(self):
        self.assertTrue(bar())

而python3 -m unittest测试将不会产生日志输出。

因为你在Django中,你可以添加这些行到你的settings.py:

import sys
import logging

if len(sys.argv) > 1 and sys.argv[1] == 'test':
    logging.disable(logging.CRITICAL)

这样就不必在测试的每个setUp()中都添加这一行。

您还可以通过这种方式对您的测试需求进行一些方便的更改。

还有另一种“更好”或“更清晰”的方法可以向测试中添加细节,那就是创建自己的测试运行器。

就像这样创建一个类:

import logging

from django.test.simple import DjangoTestSuiteRunner
from django.conf import settings

class MyOwnTestRunner(DjangoTestSuiteRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):

        # Don't show logging messages while testing
        logging.disable(logging.CRITICAL)

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

现在添加到你的settings.py文件:

TEST_RUNNER = "PATH.TO.PYFILE.MyOwnTestRunner"
#(for example, 'utils.mytest_runner.MyOwnTestRunner')

这让您可以做另一种方法做不到的非常方便的修改,即让Django只测试您想要的应用程序。你可以通过改变test_labels来添加这一行到测试运行器:

if not test_labels:
    test_labels = ['my_app1', 'my_app2', ...]

我们使用structlog,禁用它有点复杂:

from structlog import DropEvent

def disable_logging_in_tests(_, __, event_dict):
    if len(sys.argv) > 1 and sys.argv[1] == 'test':
        raise DropEvent
    return event_dict


structlog.configure(
    processors=[
        ...
        disable_logging_in_tests,
    ]
    ...

)

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

如果你正在使用pytest:

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

LOGGING_CONFIG = None

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

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

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