Python模拟异常http.client响应

时间:2019-04-28 08:24:04

标签: python

我正在测试特定的响应代码,并希望在代码不同的情况下(例如未经授权的401)模拟一个测试用例。我正在使用Python 3.7 http.client库和pytest

到目前为止,我尝试使用@patch装饰器并使用side_effect调用函数以触发异常

我的测试用例:

from unittest import mock
from application import shorten_url

def mock_status(url):
    raise ConnectionError

@patch("application.shorten_url", side_effect=mock_status)
def test_bitly(client):
    with pytest.raises(ConnectionError) as e:
        shorten_url("something")

我的代码:

def shorten_url(url):
    conn = http.client.HTTPSConnection("api-ssl.bitly.com", timeout=2)
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer abcd",
    }

    payload = json.dumps({"long_url": url})
    conn.request("POST", "/v4/shorten", payload, headers)
    res = conn.getresponse()

    if not res.status == 201:
        raise ConnectionError

    data = json.loads(res.read())
    return data["link"]

我不太了解如何使用mockside_effect正确引发此异常。

2 个答案:

答案 0 :(得分:0)

一个朋友帮我解决了这个问题,这似乎行得通(对我来说仍然很混乱):

from unittest.mock import patch, MagicMock

@patch("http.client.HTTPSConnection")
@patch("http.client.HTTPResponse")
def test_bitly(mock_conn, mock_res):
    mock_res.status = 400
    mock_conn.getresponse = MagicMock(return_value=mock_res)

    with pytest.raises(ConnectionError):
        shorten_url("fake-url")

答案 1 :(得分:0)

我认为这个答案更容易理解。首先,我创建了一个假的 http 连接和响应:

class FakeHTTPConnection:
    def __init__(self, status):
        self.status = status

    def request(self, *args):
        # If you need to do any logic to change what is returned, you can do it in this class
        pass

    def getresponse(self):
        return FakeHTTPResponse(self.status)


class FakeHTTPResponse:
    def __init__(self, status):
        self.status = status

然后在我的测试类中,我改写了 http.client.HTTPConnection 来创建我的实例。

class TestFoo(unittest.TestCase):

    @patch('http.client.HTTPConnection', new=MagicMock(return_value=FakeHTTPConnection(200)))
    def test_foo_success(self):

        conn = http.client.HTTPConnection("127.0.0.1")
        conn.request("GET", "/endpoint")
        response = conn.getresponse()
        success = response.status == http.HTTPStatus.OK