简体   繁体   中英

Python mock exception http.client response

I'm testing for a specific response code and want to mock out a test case when the code is something different, like unauthorized 401 . I'm using the Python 3.7 http.client library and pytest

So far I tried to use the @patch decorator and call a function with side_effect to trigger the exception

my test case:

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")

my code:

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"]

I don't really understand how to raise this exception correctly using mock and side_effect .

A friend helped me with the issue, this seems to work (it's still very confusing for me):

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")

I think this answer is easier to understand. First I created a fake http connection and response:

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

Then in my test class, I overrode http.client.HTTPConnection to create my instance instead.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM