2

我试图让我的测试套件创建一个与我在开发中使用的不同的日志文件,但由于某种原因, override_settings 装饰器似乎不起作用。当我运行测试时,会写入相同的“项目/项目/调试日志文件”。我在哪里搞砸了?

# settings.py
...
LOGFILE = ROOT + '/debug_logfile'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
        'standard': {
             'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
             'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'django.utils.log.NullHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['require_debug_false']
        },
        'logfile': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': LOGFILE,
            'maxBytes': 50000,
            'backupCount': 2,
            'formatter': 'standard',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['null'],
            'propagate': True,
            'level': 'INFO',
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'clients': {
            'handlers': ['console', 'logfile'],
            'level': 'DEBUG',
        },
        # display the db queries
        #'django.db.backends': {
        #    'handlers': ['console'],
        #    'level': 'DEBUG',
        #}
    }
}

# clients.management.commands.remindmanagers.py

class Command(BaseCommand):
    help = 'Creates task reminders and send emails to account and senior \
            managers when their client\'s contracts are about to expire'

    def handle(self, *args, **kwargs):
        three_months = datetime.date.today() + datetime.timedelta(days=90)
        # get all contracts that will be completed in the next 3 months
        contracts = Contract.objects.filter(finish__lte=three_months
                                   ).exclude(notices_left=0)

        if not contracts.exists():
            log.info('Tried running but there are no contracts about to expire.')
            return 0
        ...

# tests.test_clients

...
from django.core.management import call_command

@override_settings(LOGFILE=settings.ROOT + "/test_logfile")
class ClientCommandTest(BaseTestCase):
    def _file_exists(file_path):
        return os.path.exists(file_path)

    def test_remindmanagers_no_contracts(self):
        args = []
        kwargs = {}
        #self.assertFalse()
        # since there are no contracts yet, this should create an entry in ROOT + /logfile
        call_command('remindmanagers', *args, **kwargs)                                      # this should log in project/project/test_logfile not debug_logfile
4

2 回答 2

1

override_settings是不够的。因为日志记录是在override_settings生效之前配置的。调用configure_logging更改日志记录设置,不要忘记返回原始设置。

看下面的例子:

设置.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'formatter1': {
            'format': 'settings logger: {message}',
            'style': '{',
        },
    },
    'handlers': {
        'stream': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'formatter1',
        },
    },
    'loggers': {
        'test_logging_override': {
            'handlers': ['stream'],
            'level': 'DEBUG',
            'propogate': True,
        },
    },
}

测试.py

from django.test import TestCase, override_settings

class TestLoggingOverride(TestCase):
    def test_logging_override(self):
        logger = logging.getLogger('test_logging_override')
        logger.debug('one')  # settings logger: one
        with override_settings(LOGGING={
            'version': 1,
            'disable_existing_loggers': False,
            'formatters': {
                'formatter1': {
                    'format': 'overridden logger: {message}',  # !!!!
                    'style': '{',
                },
            },
            'handlers': {
                'stream': {
                    'level': 'DEBUG',
                    'class': 'logging.StreamHandler',  # 'class': 'logging.FileHandler'
                    # 'filename': 'path/to/file',  # in case of FileHandler
                    'formatter': 'formatter1',
                },
            },
            'loggers': {
                'test_logging_override': {
                    'handlers': ['stream'],
                    'level': 'DEBUG',
                    'propogate': True,
                },
            },
        }):
            logger.debug('two')  # settings logger: two
            configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)  # really change settings
            logger.debug('three')  # overridden logger: three
        logger.debug('four')  # overridden logger: four
        configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)  # return to native settings
        logger.debug('five')  # settings logger: five

此外,您可以编写日志记录测试。

from unittest.mock import MagicMock, patch, call

class TestLoggingOverride(TestCase):
    @patch(
         target='sys.stderr',
         wraps=sys.stderr,  # wraps all of sys.stderr. Remove this line, if you want to disable writing to stderr in this test
     )
     def test_patched_stream_logger(self, mocked_stderr):
         logger = logging.getLogger('test_logging_override')
         with override_settings(LOGGING={
             'version': 1,
             'disable_existing_loggers': False,
             'formatters': {
                 'formatter1': {
                     'format': 'overridden logger: {message}',  # !!!!
                     'style': '{',
                 },
             },
             'handlers': {
                 'stream': {
                     'level': 'DEBUG',
                     'class': 'logging.StreamHandler',
                     'formatter': 'formatter1',
                 },
             },
             'loggers': {
                 'test_logging_override': {
                     'handlers': ['stream'],
                     'level': 'DEBUG',
                     'propogate': True,
                 },
             },
         }):
             configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)  # really change settings
             logger.debug('lorem ipsum')
         configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)  # return to native settings
         self.assertEqual(
             mocked_stderr.method_calls,
             [call.flush(),
              call.flush(),
              call.write('overridden logger: lorem ipsum\n'),
              call.flush(),
              call.flush(),
              call.flush(),
              call.flush()]
         )
         # print(mocked_stderr.method_calls)
于 2020-09-23T07:36:24.327 回答
0

您的LOGGINGdict 文字包含变量LOGFILE,在处理 dict 文字时会立即对其进行评估。通过稍后覆盖LOGFILE,您不会更改LOGGINGdict 中的条目,因为LOGFILE字符串只是被替换了;字符串本身没有发生变异,因此您最终LOGFILE只需指向另一个字符串。

我认为您应该能够使用新文件名仅覆盖日志文件处理程序,如下所示:

@override_settings(LOGGING={
  'handlers': {
    'logfile': {
       'filename': settings.ROOT + "/test_logfile"
    }
  }
})
class ClientCommandTest(BaseTestCase):
  ...
于 2017-12-15T10:33:44.703 回答