模仿一个函数以引发一个 Exception 来测试一个除外块

我有一个函数(foo) ,它调用另一个函数(bar)。如果调用 bar()引发 HttpError,我想处理它特别是如果状态代码是404,否则重新引发。

我试图围绕这个 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实例的 side_effect设置为 Exception类,以使模拟函数引发错误。

我还看了一些其他相关的 StackOverflow 问答,看起来我正在做同样的事情,他们正在做导致和异常提出了他们的模拟。

为什么设置 barMockside_effect不会导致预期的 Exception升高?如果我正在做一些奇怪的事情,我应该如何去测试逻辑在我的 except块?

179499 次浏览

您的 mock 引发了异常,但是缺少 error.resp.status值。不要使用 return_value,只要告诉 Mock status是一个属性:

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

Mock()的其他关键字参数被设置为结果对象的属性。

我把你的 foobar的定义放在一个 my_tests模块中,添加到 HttpError中,这样我也可以使用它,然后你的测试就可以运行成功了:

>>> 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()设置。