Как я должен проверить, что несколько функций были вызваны в цикле? - PullRequest
0 голосов
/ 14 ноября 2018

Как я могу убедиться, что все обработчики были вызваны в цикле?Лучшее, что я придумал, - это смоделировать функцию fake_handler и проверить, что эта функция вызывается определенное количество раз, но я думаю, что может быть лучшее решение.

class MessageHandler:
    def __init__(self, handlers=None):
        self.handlers = handlers or []

    def handle(self, event, body):
        for handler in self.handlers:
            handler(event, body)

Тесты:

def fake_handler(*args, **kwargs):
    pass


class TestMessageHandler(TestCase):
    @patch('tests.test_handlers.fake_handler')
    def test_handle(self, fake_handler_mock):
        messages = MessageHandler([fake_handler_mock, fake_handler_mock])
        messages.handle(None, None)
        self.assertEqual(fake_handler_mock.call_count, 2)

1 Ответ

0 голосов
/ 14 ноября 2018

Я вижу ряд проблем в вашем тесте, в итоге вы не должны вносить исправления, и вы тестируете слишком мало.Позвольте мне заняться ими один за другим.

Не исправляйте

Действительно, это огромная возможность сделать ошибки или попасть в некоторые из многочисленных предостережений.Практически каждый урок начинается с использования исправлений для тестирования кода, который сложно протестировать.Но ваш код тестируемый, и он вам не нужен, это также будет работать:

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(None, None)
    self.assertEqual(handler.call_count, 2)

Проверьте аргументы, передаваемые в вызовах mocks

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

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(None, None)
    self.assertEqual(
        handler.mock_calls,
        [mock.call(None, None), mock.call(None, None)]
    )

На самом деле проверьте аргументы

Сейчас мы проверяем, что None передается обработчикам, но и событие, иbody - это None, а все остальное тоже может быть None, поэтому мы не знаем, действительно ли код делает правильный вызов.Лучше, если мы будем использовать разные уникальные значения для каждого аргумента.

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    self.assertEqual(
        handler.mock_calls,
        [mock.call(mock.sentinel.event, mock.sentinel.body),
         mock.call(mock.sentinel.event, mock.sentinel.body)]
    )

Тест с разными обработчиками

Наличие одного и того же обработчика дважды является угловым случаем.Даже если вы захотите сохранить этот тест (или изменить его; действительно ли вы хотите разрешить дублированные обработчики?), Вы действительно хотите протестировать общий случай, когда обработчики отличаются.

def test_handle(self):
    handler1 = mock.Mock(name='handler1')
    handler2 = mock.Mock(name='handler2')
    messages = MessageHandler([handler1, handler2])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    handler1.assert_called_once_with(
        mock.sentinel.event, mock.sentinel.body
    )
    handler2.assert_called_once_with(
        mock.sentinel.event, mock.sentinel.body
    )

Проверьте, чтообработчики вызываются по порядку

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

def test_handle(self):
    handlers_parent = mock.Mock(name='handlers_parent')
    handler1 = handlers_parent.handler1
    handler2 = handlers_parent.handler2
    messages = MessageHandler([handler1, handler2])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    self.assertEqual(
        handlers_parent.mock_calls,
        [mock.call.handler1(mock.sentinel.event, mock.sentinel.body),
         mock.call.handler2(mock.sentinel.event, mock.sentinel.body)]
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...