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

Издевательство над функцией для исключения исключения для проверки исключающего блока

У меня есть функция (foo), которая вызывает другую функцию (bar). Если вызов bar() вызывает HttpError, я хочу обработать его специально, если код состояния равен 404, иначе re-raise.

Я пытаюсь написать некоторые модульные тесты вокруг этой функции foo, издеваясь над вызовом bar(). К сожалению, я не могу получить издевательский вызов bar(), чтобы поднять исключение, которое было захвачено моим блоком except.

Вот мой код, который иллюстрирует мою проблему:

import unittest
import mock
from apiclient.errors import HttpError


class FooTests(unittest.TestCase):
    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnResultOfBar_whenBarSucceeds(self, barMock):
        barMock.return_value = True
        result = foo()
        self.assertTrue(result)  # passes

    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnNone_whenBarRaiseHttpError404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 404}), 'not found')
        result = foo()
        self.assertIsNone(result)  # fails, test raises HttpError

    @mock.patch('my_tests.bar')
    def test_foo_shouldRaiseHttpError_whenBarRaiseHttpErrorNot404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 500}), 'error')
        with self.assertRaises(HttpError):  # passes
            foo()

def foo():
    try:
        result = bar()
        return result
    except HttpError as error:
        if error.resp.status == 404:
            print '404 - %s' % error.message
            return None
        raise

def bar():
    raise NotImplementedError()

Я следил за Mock docs, которые говорят, что вы должны установить side_effect экземпляра Mock в класс Exception, чтобы функция mocked вызывает ошибку.

Я также посмотрел на некоторые другие связанные StackOverflow Q & As, и похоже, что я делаю то же самое, что они делают, чтобы вызвать и исключение, которое должно быть вызвано их макетом.

Почему установка side_effect в barMock не приводит к повышению ожидаемого Exception? Если я делаю что-то странное, как я должен идти о тестировании логики в блоке except?

4b9b3361

Ответ 1

Ваш макет поднимает исключение просто отлично, но значение error.resp.status отсутствует. Вместо использования return_value просто скажите Mock, что status является атрибутом:

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')

Дополнительные аргументы ключевого слова для Mock() устанавливаются как атрибуты результирующего объекта.

Я помещаю ваши определения foo и bar в модуль my_tests, добавленный в HttpError class, поэтому я может использовать его тоже, и ваш тест может быть достигнут успеха:

>>> from my_tests import foo, HttpError
>>> import mock
>>> with mock.patch('my_tests.bar') as barMock:
...     barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
...     result = my_test.foo()
... 
404 - 
>>> result is None
True

Вы даже можете увидеть линейный прогон print '404 - %s' % error.message, но я думаю, вы хотели использовать вместо него error.content; что атрибут HttpError() задает из второго аргумента, во всяком случае.