Издевательство над функцией для исключения исключения для проверки исключающего блока
У меня есть функция (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
?
Ответы
Ответ 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()
задает из второго аргумента, во всяком случае.