Mocking a function to raise an Exception to test an except block(模拟函数以引发异常以测试 except 块)
问题描述
我有一个函数 (foo),它调用另一个函数 (bar).如果调用bar()引发了HttpError,如果状态码是404我想特别处理,否则重新引发.
I have a function (foo) which calls another function (bar). If invoking bar() raises an HttpError, I want to handle it specially if the status code is 404, otherwise re-raise.
我正在尝试围绕这个 foo 函数编写一些单元测试,模拟对 bar() 的调用.不幸的是,我无法获得对 bar() 的模拟调用来引发我的 except 块捕获的异常.
I am trying to write some unit tests around this foo function, mocking out the call to bar(). Unfortunately, I am unable to get the mocked call to bar() to raise an Exception which is caught by my except block.
这是说明我的问题的代码:
Here is my code which illustrates my problem:
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 类,以使模拟函数引发错误.
I followed the Mock docs which say that you should set the side_effect of a Mock instance to an Exception class to have the mocked function raise the error.
我还查看了一些其他相关的 StackOverflow Q&As,看起来我正在做与他们正在做的事情相同的事情,以导致他们的模拟引发异常.
I also looked at some other related StackOverflow Q&As, and it looks like I am doing the same thing they are doing to cause and Exception to be raised by their mock.
- https://stackoverflow.com/a/10310532/346561
 - 如何使用 Python Mock 引发异常 - 但将 Errno 设置为给定值
 
为什么设置 barMock 的 side_effect 不会引发预期的 Exception?如果我在做一些奇怪的事情,我应该如何在我的 except 块中测试逻辑?
Why is setting the side_effect of barMock not causing the expected Exception to be raised? If I am doing something weird, how should I go about testing logic in my except block?
推荐答案
你的 mock 可以很好地引发异常,但是缺少 error.resp.status 值.与其使用 return_value,不如告诉 Mock status 是一个属性:
Your mock is raising the exception just fine, but the error.resp.status value is missing. Rather than use return_value, just tell Mock that status is an attribute:
barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
Mock() 的附加关键字参数被设置为结果对象的属性.
Additional keyword arguments to Mock() are set as attributes on the resulting object.
我将您的 foo 和 bar 定义放在 my_tests 模块中,并添加到 HttpError class 所以我可以使用它也一样,然后你的测试就可以成功了:
I put your foo and bar definitions in a my_tests module, added in the HttpError class so I could use it too, and your test then can be ran to success:
>>> 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() 从第二个参数设置的属性.
You can even see the print '404 - %s' % error.message line run, but I think you wanted to use error.content there instead; that's the attribute HttpError() sets from the second argument, at any rate.
这篇关于模拟函数以引发异常以测试 except 块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:模拟函数以引发异常以测试 except 块
				
        
 
            
        - 我如何透明地重定向一个Python导入? 2022-01-01
 - 检查具有纬度和经度的地理点是否在 shapefile 中 2022-01-01
 - 我如何卸载 PyTorch? 2022-01-01
 - 如何使用PYSPARK从Spark获得批次行 2022-01-01
 - 使用公司代理使Python3.x Slack(松弛客户端) 2022-01-01
 - YouTube API v3 返回截断的观看记录 2022-01-01
 - ";find_element_by_name(';name';)";和&QOOT;FIND_ELEMENT(BY NAME,';NAME';)";之间有什么区别? 2022-01-01
 - 使用 Cython 将 Python 链接到共享库 2022-01-01
 - CTR 中的 AES 如何用于 Python 和 PyCrypto? 2022-01-01
 - 计算测试数量的Python单元测试 2022-01-01
 
