Python Django에서 유닛 테스트를 실행하는 동안 로깅을 비활성화하려면 어떻게 해야 합니까?
저는 Django 어플리케이션을 테스트하기 위해 간단한 유닛 테스트 기반의 테스트 러너를 사용하고 있습니다.
응용 프로그램 자체가 설정에서 기본 로거를 사용하도록 구성되어 있습니다.다음을 사용하여 py:
logging.basicConfig(level=logging.DEBUG)
그리고 내 애플리케이션 코드에서 다음을 사용합니다.
logger = logging.getLogger(__name__)
logger.setLevel(getattr(settings, 'LOG_LEVEL', logging.DEBUG))
단, unittests 실행 시 테스트 결과 출력이 흐트러지지 않도록 로깅을 해제하고 싶습니다.테스트를 실행할 때 애플리케이션별 로거가 콘솔에 데이터를 쓰지 않도록 글로벌하게 로깅을 끄는 간단한 방법이 있습니까?
logging.disable(logging.CRITICAL)
가 "의 합니다.CRITICAL
은 다시 할 수
logging.disable(logging.NOTSET)
장고에 있기 때문에, 이러한 행을 설정에 추가할 수 있습니다.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', ...]
테스트를 실행할 때 애플리케이션별 로거가 콘솔에 데이터를 쓰지 않도록 글로벌하게 로깅을 끄는 간단한 방법이 있습니까?
다른 답변은 로깅 인프라스트럭처를 글로벌하게 설정하여 "콘솔에 글을 쓰는 것"을 방지합니다.이것은 효과가 있지만 나는 그것이 너무 무뚝뚝한 접근이라고 생각한다.이 접근방식은 로그가 콘솔에 출력되지 않도록 하기 위해 필요한 설정 변경만 수행하는 것입니다.그래서 커스텀 로깅 필터를 추가합니다.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
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,
},
}
}
최종 결과: 테스트 중에는 콘솔에는 아무것도 표시되지 않지만 다른 모든 것은 그대로 유지됩니다.
왜 그럴까?
특정 상황에서만 트리거되는 로깅 명령이 포함된 코드를 설계하고 문제가 발생했을 때 진단에 필요한 정확한 데이터를 출력합니다.따라서 나는 그들이 해야 할 일을 하는 것을 테스트하고, 따라서 로깅을 완전히 비활성화할 수 없다.일단 소프트웨어가 실가동되면 로그에 기록될 것으로 생각했던 것이 기록되지 않는 것을 확인하고 싶지 않습니다.
또한 일부 테스트 실행자(예를 들어 노즈)는 테스트 중에 로그를 캡처하여 로그의 관련 부분을 테스트 실패와 함께 출력합니다.이것은 테스트가 실패한 이유를 알아내는 데 유용합니다.로깅이 완전히 꺼지면 캡처할 수 있는 항목이 없습니다.
나는 Hassek의 커스텀 테스트 러너 아이디어가 마음에 든다.: " " " " "DjangoTestSuiteRunner
1.6이 테스트 주자는 1.6+로 되었습니다.장고 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)
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)
하는 예쁘고 .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 tests
로깅 출력은 생성되지 않습니다.
단순한 메서드 데코레이터를 사용하여 특정 테스트 방법에서만 로깅을 비활성화합니다.
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
로그를 원할 때도 있고 그렇지 않을 때도 있습니다.는 제 코드에 .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
으로는 ★★★★★★★★★★★★★★★★★★★★★★★★★critical
삭제:
$ python ./manage.py tests --no-logs
> Disabling logging levels of CRITICAL and below.
연속적인 통합 흐름의 테스트 속도를 높이고 싶은 경우 매우 유용합니다.
모듈 전체의 로깅을 디세블로 합니다.
import logging
def setUpModule():
"""Disable logging while doing these tests."""
logging.disable()
def tearDownModule():
"""Re-enable logging after doing these tests."""
logging.disable(logging.NOTSET)
class TestFoo(unittest.TestCase):
def test_foo(self):
pass
★★★★★★★★★를 사용하고 있는 경우는pytest
:
pytest는 로그 메시지를 캡처하여 실패한 테스트에 대해서만 표시하므로 일반적으로 로깅을 사용하지 않도록 설정하지 않습니다.따로 ㄴ, ㄴ는 걸 쓰세요.settings.py
"시험용 파일")test_settings.py
LOGGING_CONFIG = None
그러면 Django는 로깅 설정을 모두 건너뛰도록 지시됩니다.LOGGING
설정은 무시되며 설정에서 삭제할 수 있습니다.
이 방법에서는 통과된 테스트에 대한 로깅을 얻을 수 없으며 실패한 테스트에 대해 사용 가능한 로깅을 모두 얻을 수 있습니다.
는 '로깅'이 됩니다.pytest
. 에서 대로 할 수 pytest
★★★★★★★★★★★★★★★★★★★★★」tox.ini
) 하려면 , 를 log_level = 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
료됩니니다다
은 유닛 의 최상위 수 .__init__.py
파일입니다. 이렇게 하면 유닛 테스트 스위트에서 로깅이 글로벌하게 비활성화됩니다.
# tests/unit/__init__.py
import logging
logging.disable(logging.CRITICAL)
일부 테스트에는 로그 출력에 대한 설명이 포함되어 있기 때문에 로그 수준을 변경하면 로그 출력이 중단됩니다.요.LOGGING
테스트 실행 시 NullHandler를 사용하는 설정:
if 'test' in sys.argv:
_LOG_HANDLERS = ['null']
else:
_LOG_HANDLERS = ['console']
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
},
'loggers': {
'django': {
'handlers': _LOG_HANDLERS,
'propagate': True,
'level': 'INFO',
},
}
}
unittest에 대해 setUp() 및 tearDown()에서 반복적으로 on/off를 하고 싶지 않은 경우(이유를 알 수 없음), 클래스별로 1회만 실행할 수 있습니다.
import unittest
import logging
class TestMyUnitTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
logging.disable(logging.CRITICAL)
@classmethod
def tearDownClass(cls):
logging.disable(logging.NOTSET)
b.h.
나는 매우 쾌적하게 일을 한다.py:
import confing
# disable logging for tests
[logging.disable(level) for level in [logging.DEBUG,
logging.INFO,
logging.ERROR,
logging.CRITICAL]]
에는 설정 .settings/test.py
테스트용으로 특별히 작성된 것은 다음과 같습니다.
from .base import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test_db'
}
}
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
LOGGING = {}
.DJANGO_SETTINGS_MODULE=settings.test
로로 합니다./etc/environment
.
테스트, 개발 및 실가동용으로 다른 initializer 모듈이 있는 경우 Initialser에서 모든 모듈을 비활성화하거나 리다이렉트할 수 있습니다.local.py, test.py 및 production.py가 모두 common.y에서 상속됩니다.
common.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로 대체되고 로깅이 계속되지만 프로덕션 코드 베이스는 건드리지 않아도 됩니다.
pytest를 사용하는 경우 매우 유용한 pytest-mock 플러그인을 설치하고 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")
2021년 이후가 궁금할 경우 잘못된 질문을 할 수 있습니다.
최신 버전의 Django*에서는 초기 설정에서는 테스트로 화면에 로그가 표시되지 않습니다.따라서 이 질문에 대답할 경우 "뭔가 잘못 구성되었습니다"가 정답이 될 수 있습니다.그 이유는 (기본값) 다음과 같습니다.
가 에서 한 LOGGING['loggers']
에 의해 처리됩니다."console"
핸들러, 테스트에서는 화면에 로그가 표시되지 않습니다.
어차피 시험에서 뭔가 나오면
- 이 로거 이름과
settings.LOGGING
- 를 사용하여 테스트를 실행하고 있습니다.
DEBUG=True
) ('오버라이드') "require_debug_true"
콘솔 핸들러의 필터에서 선택합니다.
*현대판 의미: 2.1 이상(고대가 아님)
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,
]
...
)
언급URL : https://stackoverflow.com/questions/5255657/how-can-i-disable-logging-while-running-unit-tests-in-python-django
'source' 카테고리의 다른 글
재귀 SQL 쿼리의 무한 루프 (0) | 2023.01.15 |
---|---|
두 날짜 사이의 시간을 찾을 수 없습니다 MySQL (0) | 2023.01.15 |
달력이 잘못된 달을 반환함 (0) | 2023.01.15 |
Python 모듈의 버전을 확인하려면 어떻게 해야 하나요? (0) | 2023.01.15 |
JavaScript를 난독화(보호)하려면 어떻게 해야 합니까? (0) | 2023.01.15 |