pythondjangonosedjango-nose

How to prevent django tests from showing sys.stdout messages?


My problem is that since I have added logging to my django app when I run my unit tests all my log messages show in the console. I use nose as test runner. Its usual behaviour was to capture sys.stdout, only show console output if a test failed and show it at the end.

I used to have this output when running my tests:

........
Ran 8 tests in 0.876s

OK
Destroying test database for alias 'default'...

This is the output I am getting now when I run python manage.py test accounts:

...log message
.log message
....log message
Ran 8 tests in 1.034s

OK
Destroying test database for alias 'default'...

This has started happening when I have added logging using Python standard logging library to my code. I changed my settings.py and views.py. Below you can check what I have changed exactly.

Can someone help me keep my logging but avoid the annoying extra output when I run tests?

Added to settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'stream': sys.stdout,
        },
    },
    'loggers': {
        '': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

Added to my views

import logging

logger = logging.getLogger(__name__)

logger.info("log message")

The command django uses to run my tests

nosetests accounts/ --with-coverage --cover-package=accounts,keys, utils --cover-html --cover-erase --logging-filter='selenium' --verbosity=1

Configuration of nose test runner in settings.py (this was the same when it was working)

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
NOSE_ARGS = [
    '--with-coverage',
    '--cover-package=accounts,keys, utils',
    '--cover-html',
    '--cover-erase',
    "--logging-filter='selenium'",
]

Solution

  • You should write a custom test runner to disable logging or change the level.

    import logging
    
    from django_nose import NoseTestSuiteRunner
    
    
    class DisableLoggingNoseTestSuiteRunner(NoseTestSuiteRunner):
        """
        Disable the test runner log level below `logging.CRITICAL`.
        """
        def run_tests(self, *args, **kwargs):
            # Disable logging below critical
            logging.disable(logging.CRITICAL)
            super(DisableLoggingNoseTestSuiteRunner, self).run_tests(*args, **kwargs)
    

    You also have to change your settings.pyto use that test runner.

    TEST_RUNNER = 'package_where_you_place_it.DisableLoggingNoseTestSuiteRunner'