Python模拟requests.post抛出异常

7
使用Python 3.5,requests==2.18.4,Flask==0.12.2,urllib3==1.22
在我的主文件server.py中有一个名为some_method的方法,它应该使用一些数据向某个URL进行POST请求:
def some_method(url, data):
    ...
    error = None
    try:
        response = requests.post(url, json=data)
    except requests.exceptions.ConnectionError as e:
        ...
        app.logger.error(...)
        response = None
        error = str(e)
    return error, response

服务器文件定义了:app = Flask(__name__),并从@app.route(... methods=['PATCH'])调用了some_method方法。
如果此方法抛出错误,则路由最终将返回500
测试从测试文件中导入应用程序:import serverapp = server.app,使用unittest和导入mock.patch
我能够测试整个应用程序的行为,并通过一个测试展示当方法返回错误时应用程序路由表现如预期,同时检查路由是否在正确位置终止:
class ServerTestCase(unittest.TestCase):
    ...
    @patch('server.some_method')
    def test_route_response_status_500_when_throws(self, mock_response):
        mock_response.return_value = 'some_error_string', None
        response = self.app.patch(some_url, some_data, content_type='application/json')
        self.assertEqual(response.status_code, 500)

然而,我希望有另一个测试来独立测试some_method

  1. 模拟 requests.post 抛出 requests.exceptions.ConnectionError
  2. 证明该方法记录了一个错误(我知道我可以模拟我的 app.logger 并在执行期间断言它是否已记录)

1
那你卡在哪里了?你可以很好地模拟requests.post,并且可以通过设置side_effects属性使模拟引发异常。 - Martijn Pieters
1个回答

16

模拟 requests.post 函数,并在模拟中将 side_effect 属性 设置为所需的异常:

@patch('requests.post')
def test_request_post_exception(self, post_mock):
    post_mock.side_effect = requests.exceptions.ConnectionError()
    # run your test, code calling `requests.post()` will trigger the exception.

来自链接文档:

This can either be a function to be called when the mock is called, an iterable or an exception (class or instance) to be raised.

[...]

An example of a mock that raises an exception (to test exception handling of an API):

>>> mock = Mock()
>>> mock.side_effect = Exception('Boom!')
>>> mock()
Traceback (most recent call last):
  ...
Exception: Boom!
(加粗为本人所加)。

这也在 快速指南 中有涵盖:

side_effect allows you to perform side effects, including raising an exception when a mock is called:

>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
 ...
KeyError: 'foo'

谢谢!我正在按照您在回复中提到的做,但是我遇到了一些错误:
  1. requests.exceptions.ConnectionError -> requests.exceptions.ConnectionError()
  2. 我尝试了很多种 patch 的变化形式,也试过对象,但最终改成了 @patch('requests.post')
- camelBack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接