模拟函数以引发异常以测试除块
Posted
技术标签:
【中文标题】模拟函数以引发异常以测试除块【英文标题】:Mocking a function to raise an Exception to test an except block 【发布时间】:2015-04-03 00:46:18 【问题描述】:我有一个函数 (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 docs,它说您应该将Mock
实例的side_effect
设置为Exception
类,以使模拟函数引发错误。
我还查看了一些其他相关的 *** 问答,看起来我正在做与他们正在做的相同的事情,以导致他们的模拟引发异常。
https://***.com/a/10310532/346561 How to use Python Mock to raise an exception - but with Errno set to a given value为什么设置barMock
的side_effect
不会导致预期的Exception
被提升?如果我在做一些奇怪的事情,我应该如何在 except
块中测试逻辑?
【问题讨论】:
我很确定您的异常 is 正在引发,但我不确定您如何在那里设置resp.status
代码。 HTTPError
来自哪里?
@MartijnPieters HttpError
是我们在 GAE 中使用的 Google's apiclient
lib 中定义的类。它的__init__
是用参数(resp, content)
定义的,所以我试图为响应创建一个模拟实例,并指定适当的状态代码。
对,原来是this class;但是您不需要用户return_value
; resp
未被调用。
我在没有使用HttpError
的情况下再次尝试了我的代码,而是尝试使用常规的Exception
实例。这完美地工作。这意味着它必须与我如何配置HttpError
实例有关,可能与我如何为响应创建Mock
实例有关。
【参考方案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()
。
【讨论】:
side_effect
是关键部分
HttpError(mock.Mock(status=404), 'not found') 是做什么的?对我来说,它没有将状态码设置为 404,它仍然是 None。
@Yang:你用的是google-api-client
exception class吗?如果不详细说明您在做什么,我将无法帮助您。 mock.Mock(status=404)
表达式创建一个具有.status
属性的模拟对象,HttpError
将其存储为resp
属性。在问题中,然后以error.resp.status
访问。以上是关于模拟函数以引发异常以测试除块的主要内容,如果未能解决你的问题,请参考以下文章