Подтвердить что ты не робот

Как проверить, зарегистрировано ли какое-либо сообщение журнала в тестовом примере Django?

Я хочу убедиться, что определенное условие в моем коде вызывает запись журнала в журнал django. Как я могу это сделать с помощью модульной системы тестирования Django?

Есть ли место, где я могу проверять зарегистрированные сообщения, аналогично тому, как я могу проверять отправленные электронные письма? Мой unit test расширяет django.test.TestCase.

4b9b3361

Ответ 1

Используя модуль mock для издевательств модуля регистрации или объекта журнала. Когда вы это сделаете, проверьте аргументы, с которыми вызывается функция ведения журнала.

Например, если код выглядит следующим образом:

import logging

logger = logging.getLogger('my_logger')

logger.error("Your log message here")

он выглядел бы так:

from unittest.mock import patch # For python 2.x use from mock import patch

@patch('this.is.my.module.logger')
def test_check_logging_message(self, mock_logger):
    mock_logger.error.assert_called_with("Your log message here")

Ответ 2

Вы также можете использовать assertLogs от django.test.TestCase

При кодировании

import logging

logger = logging.getLogger('my_logger')

def code_that_throws_error_log():
    logger.error("Your log message here")

Это тестовый код.

with self.assertLogs(logger='my_logger', level='ERROR') as cm:

    code_that_throws_error_log()

    self.assertIn(
        "ERROR:your.module:Your log message here",
        cm.output
    )

Это позволяет избежать исправления только для журналов.

Ответ 3

Обычный способ макетирования объекта логгера (см. великолепный ответ симеона Виссера, глава) немного сложен в том смысле, что он требует теста, чтобы макетировать логирование во всех местах, которые он сделал. Это неудобно, если регистрация ведется из более чем одного модуля или в коде, который вам не принадлежит. Если запись в модуль происходит из-за изменения имени, это нарушит ваши тесты.

В великолепный пакетtestfixtures входят инструменты для добавления обработчика ведения журнала, который собирает все сгенерированные сообщения журнала, независимо от того, откуда они приходят. Захваченные сообщения могут быть позже опрошены тестом. В простейшем виде:

Предполагается, что тестируется код, который регистрирует:

import logging
logger = logging.getLogger()
logger.info('a message')
logger.error('an error')

Тестом для этого будет:

from testfixtures import LogCapture
with LogCapture() as l:
    call_code_under_test()
l.check(
    ('root', 'INFO', 'a message'),
    ('root', 'ERROR', 'an error'),
)

Слово "корень" означает, что запись в журнал была отправлена через регистратор, созданный с использованием logging.getLogger() (то есть без аргументов.) Если вы передадите arg в getLogger (__name__ является обычным), этот аргумент будет использоваться вместо корня.

Тесту не важно, какой модуль создал логи. Это может быть субмодуль, вызываемый нашим тестируемым кодом, включая сторонний код.

Тест утверждает о фактическом сгенерированном сообщении журнала, в отличие от метода насмешки, который утверждает о переданных аргументах. Они будут отличаться, если в вызове logging.info используются строки формата '% s' с дополнительными аргументами, которые вы не раскрываете сами (например, используйте logging.info('total=%s', len(items)) вместо logging.info('total=%s' % len(items)), что вам следует. Это не требует дополнительной работы и допускает гипотетическую гипотезу). будущие службы агрегации журналирования, такие как 'Sentry', будут работать правильно - они видят, что "total = 12" и "total = 43" - это два экземпляра одного и того же сообщения журнала. Именно поэтому Pylint предупреждает о последней форме logging.info позвоните.)

LogCapture включает в себя средства для фильтрации журналов и тому подобное. Его родительский пакет 'testfixtures', написанный Крисом Уизерсом, еще одним замечательным главой, включает в себя множество других полезных инструментов тестирования. Документация здесь: http://pythonhosted.org/testfixtures/logging.html

Ответ 4

В Django есть замечательная функция менеджера контекста, которая называется patch_logger.

from django.test.utils import patch_logger

тогда в вашем тестовом случае:

with patch_logger('logger_name', 'error') as cm:
    self.assertIn("Error message", cm)

где:

  • logger_name это имя регистратора (дух)
  • error - уровень журнала
  • cm - список всех сообщений журнала

Подробнее:

https://github.com/django/django/blob/2.1/django/test/utils.py#L638

Это должно работать так же для django & lt; 2.0, независимо от версии Python (если она поддерживается dj)

Ответ 5

Если вы используете тестовые классы, вы можете использовать следующее решение:

import logger

from django.test import TestCase


class MyTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super(MyTest, cls).setUpClass()
        cls.logging_error = logging.error
        logging.error = cls._error_log

    @classmethod
    def tearDownClass(cls):
        super(MyTest, cls).tearDownClass()
        logging.error = cls.logging_error

    @classmethod
    def _error_log(cls, msg):
      cls.logger = msg

    def test_logger(self):
        self.assertIn('Message', self.logger)

Этот метод заменяет функцию error модуля logging вашим пользовательским методом только для целей тестирования и ставит stdout в переменную cls.logger, которая доступна в каждом тестовом случае, вызывая self.logger. В конце он возвращает изменения, помещая error функцию из модуля logging назад.