How can I disable logging while running unit tests in Python Django?

后端 未结 15 773
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-07 09:50

I am using a simple unit test based test runner to test my Django application.

My application itself is configured to use a basic logger in settings.py using:

<
相关标签:
15条回答
  • 2020-12-07 10:34

    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', ...]
    
    0 讨论(0)
  • 2020-12-07 10:34

    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.

    0 讨论(0)
  • 2020-12-07 10:37

    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)
    
    0 讨论(0)
  • 2020-12-07 10:38

    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)
    
    0 讨论(0)
  • 2020-12-07 10:38

    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)
    
    0 讨论(0)
  • 2020-12-07 10:40

    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',
            },
        }
    }
    
    0 讨论(0)
提交回复
热议问题