1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
.. _introduction:
`Github <https://github.com/gabrielfalcao/HTTPretty>`_
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 <http://fakeweb.rubyforge.org/>`_.
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
<http://en.wikipedia.org/wiki/Monkey_patch>`_ 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.
|