.. _introduction: `Github `_ What is HTTPretty ? ################### .. highlight:: python Once upon a time a python developer wanted to use a RESTful api, everything was fine but until the day he needed to test the code that hits the RESTful API: what if the API server is down? What if its content has changed ? Don't worry, HTTPretty is here for you: :: import logging import requests import httpretty from sure import expect logging.getLogger('httpretty.core').setLevel(logging.DEBUG) @httpretty.activate(allow_net_connect=False) def test_yipit_api_returning_deals(): httpretty.register_uri(httpretty.GET, "http://api.yipit.com/v1/deals/", body='[{"title": "Test Deal"}]', content_type="application/json") response = requests.get('http://api.yipit.com/v1/deals/') expect(response.json()).to.equal([{"title": "Test Deal"}]) A more technical description ============================ HTTPretty is a python library that swaps the modules :py:mod:`socket` and :py:mod:`ssl` with fake implementations that intercept HTTP requests at the level of a TCP connection. It is inspired on Ruby's `FakeWeb `_. If you come from the Ruby programming language this would probably sound familiar :smiley: Installing ========== Installing httpretty is as easy as: .. highlight:: bash :: pip install httpretty Demo #### expecting a simple response body ================================ .. code:: python import requests import httpretty def test_one(): httpretty.enable(verbose=True, allow_net_connect=False) # enable HTTPretty so that it will monkey patch the socket module httpretty.register_uri(httpretty.GET, "http://yipit.com/", body="Find the best daily deals") response = requests.get('http://yipit.com') assert response.text == "Find the best daily deals" httpretty.disable() # disable afterwards, so that you will have no problems in code that uses that socket module httpretty.reset() # reset HTTPretty state (clean up registered urls and request history) making assertions in a callback that generates the response body ================================================================ .. code:: python import requests import json import httpretty @httpretty.activate def test_with_callback_response(): def request_callback(request, uri, response_headers): content_type = request.headers.get('Content-Type') assert request.body == '{"nothing": "here"}', 'unexpected body: {}'.format(request.body) assert content_type == 'application/json', 'expected application/json but received Content-Type: {}'.format(content_type) return [200, response_headers, json.dumps({"hello": "world"})] httpretty.register_uri( httpretty.POST, "https://httpretty.example.com/api", body=request_callback) response = requests.post('https://httpretty.example.com/api', headers={'Content-Type': 'application/json'}, data='{"nothing": "here"}') expect(response.json()).to.equal({"hello": "world"}) Link headers ============ Tests link headers by using the `adding_headers` parameter. .. code:: python import requests from sure import expect import httpretty @httpretty.activate def test_link_response(): first_url = "http://foo-api.com/data" second_url = "http://foo-api.com/data?page=2" link_str = "<%s>; rel='next'" % second_url httpretty.register_uri( httpretty.GET, first_url, body='{"success": true}', status=200, content_type="text/json", adding_headers={"Link": link_str}, ) httpretty.register_uri( httpretty.GET, second_url, body='{"success": false}', status=500, content_type="text/json", ) # Performs a request to `first_url` followed by some testing response = requests.get(first_url) expect(response.json()).to.equal({"success": True}) expect(response.status_code).to.equal(200) next_url = response.links["next"]["url"] expect(next_url).to.equal(second_url) # Follow the next URL and perform some testing. response2 = requests.get(next_url) expect(response2.json()).to.equal({"success": False}) expect(response2.status_code).to.equal(500) Motivation ########## When building systems that access external resources such as RESTful webservices, XMLRPC or even simple HTTP requests, we stumble in the problem: *"I'm gonna need to mock all those requests"* It can be a bit of a hassle to use something like :py:class:`mock.Mock` to stub the requests, this can work well for low-level unit tests but when writing functional or integration tests we should be able to allow the http calls to go through the TCP socket module. HTTPretty `monkey patches `_ Python's :py:mod:`socket` core module with a fake version of the module. Because HTTPretty implements a fake the modules :py:mod:`socket` and :py:mod:`ssl` you can use write tests to code against any HTTP library that use those modules.