325👍
logging.disable(logging.CRITICAL)
will disable all logging calls with levels less severe than or equal to CRITICAL
. Logging can be re-enabled with
logging.disable(logging.NOTSET)
60👍
Since you are in Django, you could add these lines to your settings.py:
import sys
import logging
if len(sys.argv) > 1 and sys.argv[1] == 'test':
logging.disable(logging.CRITICAL)
That way you don’t have to add that line in every setUp()
on your tests.
You could also do a couple of handy changes for your test needs this way.
There is another “nicer” or “cleaner” way to add specifics to your tests and that is making your own test runner.
Just create a class like this:
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)
And now add to your settings.py file:
TEST_RUNNER = "PATH.TO.PYFILE.MyOwnTestRunner"
#(for example, 'utils.mytest_runner.MyOwnTestRunner')
This lets you do one really handy modification that the other approach doesn’t, which is to make Django just tests the applications that you want. You can do that by changing the test_labels
adding this line to the test runner:
if not test_labels:
test_labels = ['my_app1', 'my_app2', ...]
- [Django]-Django staticfiles not found on Heroku (with whitenoise)
- [Django]-Django – SQL bulk get_or_create possible?
- [Django]-How to recursively query in django efficiently?
29👍
Is there a simple way to turn off logging in a global way, so that the application specific loggers aren’t writing stuff out to the console when I run tests?
The other answers prevent “writing stuff out to the console” by globally setting the logging infrastructure to ignore anything. This works but I find it too blunt an approach. My approach is to perform a configuration change which does only what’s needed to prevent logs to get out on the console. So I add a custom logging filter to my 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
And I configure the Django logging to use the filter:
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,
},
}
}
End result: when I’m testing, nothing goes to the console, but everything else stays the same.
Why Do This?
I design code that contains logging instructions that are triggered only in specific circumstances and that should output the exact data I need for diagnosis if things go wrong. Therefore I test that they do what they are supposed to do and thus completely disabling logging is not viable for me. I don’t want to find once the software is in production that what I thought would be logged is not logged.
Moreover, some test runners (Nose, for instance) will capture logs during testing and output the relevant part of the log together with a test failure. It is useful in figuring out why a test failed. If logging is completely turned off, then there’s nothing that can be captured.
- [Django]-Django can' t load Module 'debug_toolbar': No module named 'debug_toolbar'
- [Django]-Pylint "unresolved import" error in Visual Studio Code
- [Django]-Django rest framework lookup_field through OneToOneField
21👍
I like Hassek’s custom test runner idea. It should be noted that DjangoTestSuiteRunner
is no longer the default test runner in Django 1.6+, it has been replaced by the DiscoverRunner
. For default behaviour, the test runner should be more like:
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)
- [Django]-How to use Django ImageField, and why use it at all?
- [Django]-Why does DEBUG=False setting make my django Static Files Access fail?
- [Django]-Django middleware difference between process_request and process_view
15👍
I’ve found that for tests within unittest
or similar a framework, the most effective way to safely disable unwanted logging in unit tests is to enable/disable in the setUp
/tearDown
methods of a particular test case. This lets one target specifically where logs should be disabled. You could also do this explicitly on the logger of the class you’re testing.
import unittest
import logging
class TestMyUnitTest(unittest.TestCase):
def setUp(self):
logging.disable(logging.CRITICAL)
def tearDown(self):
logging.disable(logging.NOTSET)
- [Django]-Django datefield filter by weekday/weekend
- [Django]-How do I filter query objects by date range in Django?
- [Django]-Django: Using F arguments in datetime.timedelta inside a query
9👍
I am using a simple method decorator to disable logging only in a particular test method.
def disable_logging(f):
def wrapper(*args):
logging.disable(logging.CRITICAL)
result = f(*args)
logging.disable(logging.NOTSET)
return result
return wrapper
And then I use it as in the following example:
class ScenarioTestCase(TestCase):
@disable_logging
test_scenario(self):
pass
- [Django]-Equivalent of PHP "echo something; exit();" with Python/Django?
- [Django]-Django – {% csrf_token %} was used in a template, but the context did not provide the value
- [Django]-How to delete project in django
8👍
There is some pretty and clean method to suspend logging in tests with unittest.mock.patch
method.
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())
And python3 -m unittest tests
will produce no logging output.
- [Django]-Handle `post_save` signal in celery
- [Django]-Django REST framework post array of objects
- [Django]-Where to put business logic in django
3👍
Sometimes you want the logs and sometimes not. I have this code in my 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)
So if you run your test with the --no-logs
options you’ll get only the critical
logs:
$ python ./manage.py tests --no-logs
> Disabling logging levels of CRITICAL and below.
It’s very helpful if you want speedup the tests on your continuous integration flow.
- [Django]-Django Queryset with year(date) = '2010'
- [Django]-Copy a database column into another in Django
- [Django]-POST jQuery array to Django
3👍
In cases where I wish to temporarily suppress a specific logger, I’ve written a little context manager that I’ve found useful:
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
You then use it like:
class MyTestCase(TestCase):
def test_something(self):
with disable_logger('<logger name>'):
# code that causes the logger to fire
This has the advantage that the logger is re-enabled (or set back to its prior state) once the with
completes.
- [Django]-Pylint "unresolved import" error in Visual Studio Code
- [Django]-How to serve media files on Django production environment?
- [Django]-Django filter JSONField list of dicts
3👍
Disable logging for the entire module:
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
- [Django]-Are sessions needed for python-social-auth
- [Django]-Django form: what is the best way to modify posted data before validating?
- [Django]-Django annotation with nested filter
2👍
If you’re using pytest
:
Since pytest captures log messages and only displays them for failed tests, you typically don’t want to disable any logging. Instead, use a separate settings.py
file for tests (e.g., test_settings.py
), and add to it:
LOGGING_CONFIG = None
This tells Django to skip configuring the logging altogether. The LOGGING
setting will be ignored and can be removed from the settings.
With this approach, you don’t get any logging for passed tests, and you get all available logging for failed tests.
The tests will run using the logging that was set up by pytest
. It can be configured to your liking in the pytest
settings (e.g., tox.ini
). To include debug level log messages, use log_level = DEBUG
(or the corresponding command line argument).
- [Django]-How do I match the question mark character in a Django URL?
- [Django]-Django: Record with max element
- [Django]-What is related_name used for?
2👍
You can put this in the top level directory for unit tests __init__.py
file. This will disable logging globally in the unit test suite.
# tests/unit/__init__.py
import logging
logging.disable(logging.CRITICAL)
- [Django]-What's the difference between select_related and prefetch_related in Django ORM?
- [Django]-Serving Media files during deployment in django 1.8
- [Django]-IOS app with Django
2👍
Some of my tests contain assertions about log output, so changing the log level breaks them. Instead, I changed my Django LOGGING
settings to use a NullHandler when running tests:
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',
},
}
}
- [Django]-Resource temporarily unavailable using uwsgi + nginx
- [Django]-Filtering dropdown values in django admin
- [Django]-Django Rest Framework Conditional Field on Serializer
1👍
If you don’t want it repeatedly turn it on/off in setUp() and tearDown() for unittest (don’t see the reason for that), you could just do it once per class:
import unittest
import logging
class TestMyUnitTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
logging.disable(logging.CRITICAL)
@classmethod
def tearDownClass(cls):
logging.disable(logging.NOTSET)
- [Django]-Using Python's os.path, how do I go up one directory?
- [Django]-Django substr / substring in templates
- [Django]-Are Django SECRET_KEY's per instance or per app?
1👍
b.h.
for me works whell – in conftest.py:
import confing
# disable logging for tests
[logging.disable(level) for level in [logging.DEBUG,
logging.INFO,
logging.ERROR,
logging.CRITICAL]]
- [Django]-Github issues api 401, why? (django)
- [Django]-Django: guidelines for speeding up template rendering performance
- [Django]-Django proxy model and ForeignKey
0👍
In my case I have a settings file settings/test.py
created specifically for testing purposes, here’s what it looks like:
from .base import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test_db'
}
}
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
LOGGING = {}
I put an environment variable DJANGO_SETTINGS_MODULE=settings.test
to /etc/environment
.
- [Django]-How to execute a Python script from the Django shell?
- [Django]-How to change empty_label for modelForm choice field?
- [Django]-What's the purpose of Django setting ‘SECRET_KEY’?
0👍
If you have different initaliser modules for test, dev and production then you can disable anything or redirect it in the initialser. I have local.py, test.py and production.py that all inherit from common.y
common.py does all the main config including this snippet :
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,
},
}
Then in test.py I have this:
console_logger = Common.LOGGING.get('handlers').get('console')
console_logger['class'] = 'logging.FileHandler
console_logger['filename'] = './unitest.log
This replaces the console handler with a FileHandler and means still get logging but I do not have to touch the production code base.
- [Django]-Timestamp fields in django
- [Django]-Using Python's os.path, how do I go up one directory?
- [Django]-Django model one foreign key to many tables
0👍
In case you’re using pytest, you can install the super useful pytest-mock plugin and define an auto-used, session-scoped fixture that can be triggered by an 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")
- [Django]-Django + Ajax
- [Django]-Alowing 'fuzzy' translations in django pages?
- [Django]-Django rest framework: query parameters in detail_route
0👍
We use structlog, which is a bit more complicated to disable:
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,
]
...
)
- [Django]-Do we need to upload virtual env on github too?
- [Django]-Convert Django Model object to dict with all of the fields intact
- [Django]-How can I handle Exceptions raised by dango-social-auth?
-1👍
"""Module for custom test runner."""
import logging
from django.conf import settings
from django.test.runner import DiscoverRunner
class FastTestRunner(DiscoverRunner):
"""Custom Django test runner to speed up the test suite."""
def setup_test_environment(self):
"""Override the setup_test_environment method to customize the test environment.
This method is called before the test suite runs and is used to set up any necessary configurations.
In this custom runner, we disable file writes during tests by changing the default storage backend
to use Django's InMemoryStorage, which does not write files to the filesystem. Additionally, we
use a faster password hasher (MD5) to speed up test cases involving user authentication.
"""
super().setup_test_environment()
# Disable file writes during tests by using Django's FileSystemStorage
settings.STORAGES = {"default": {"BACKEND": "django.core.files.storage.InMemoryStorage"}}
# Use a faster password hasher (MD5) to speed up test cases involving user authentication
settings.PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
# disable logging below CRITICAL while testing
logging.disable(logging.CRITICAL)
- [Django]-Find object in list that has attribute equal to some value (that meets any condition)
- [Django]-Django-Bower + Foundation 5 + SASS, How to configure?
- [Django]-How to change the name of a Django app?
-2👍
You’re likely asking the wrong question if you’re wondering about this in 2021 or later
On modern versions of Django*, with the out of the box configuration, tests should not produce any logging on screen. Thus, if you’re aksing this question the real answer may be "something is misconfigured". This is because (by default):
Thus, if the loggers you use match those you have defined in LOGGING['loggers']
and being handled by the "console"
handler, tests should not produce any logging on screen.
If you see something in tests anyway, you either
- have mismatched the name of your logger with the thing you’ve defined in
settings.LOGGING
- are running tests with
DEBUG=True
(which requires an override) - have removed
"require_debug_true"
from your console handler’s filters.
*Modern versions meaning: 2.1 and up, i.e. not ancient.
- [Django]-Storing an Integer Array in a Django Database
- [Django]-Http POST drops port in URL
- [Django]-Django: How can I create a multiple select form?