diff --git a/httpretty/core.py b/httpretty/core.py index f2332008..4e31226c 100644 --- a/httpretty/core.py +++ b/httpretty/core.py @@ -25,6 +25,7 @@ # OTHER DEALINGS IN THE SOFTWARE. from __future__ import unicode_literals +from urlparse import parse_qsl import re import codecs import inspect @@ -381,7 +382,7 @@ def sendall(self, data, *args, **kw): query=s.query, last_request=request) - matcher, entries = httpretty.match_uriinfo(info) + matcher, entries = httpretty.match_uriinfo(info, request) if not entries: self._entry = None @@ -706,13 +707,14 @@ class URIMatcher(object): regex = None info = None - def __init__(self, uri, entries, match_querystring=False): + def __init__(self, uri, expected_data, entries, match_querystring=False): self._match_querystring = match_querystring if type(uri).__name__ == 'SRE_Pattern': self.regex = uri else: self.info = URIInfo.from_uri(uri, entries) + self.expected_data = expected_data self.entries = entries #hash of current_entry pointers, per method. @@ -725,6 +727,15 @@ def matches(self, info): return self.regex.search(info.full_url( use_querystring=self._match_querystring)) + def check_expected_data(self, request): + if self.expected_data is not None: + body_dict = dict(parse_qsl(request.body)) + if body_dict != self.expected_data: + raise ValueError("Body Post didn't match, expected %s, got %s" % ( + self.expected_data, + body_dict + )) + def __str__(self): wrap = 'URLMatcher({0})' if self.info: @@ -778,9 +789,10 @@ class httpretty(HttpBaseClass): _is_enabled = False @classmethod - def match_uriinfo(cls, info): + def match_uriinfo(cls, info, request): for matcher, value in cls._entries.items(): if matcher.matches(info): + matcher.check_expected_data(request) return (matcher, info) return (None, []) @@ -862,7 +874,9 @@ def register_uri(cls, method, uri, body='HTTPretty :)', adding_headers=None, forcing_headers=None, status=200, - responses=None, match_querystring=False, + expected_data=None, + responses=None, + match_querystring=False, **headers): uri_is_string = isinstance(uri, basestring) @@ -885,7 +899,7 @@ def register_uri(cls, method, uri, body='HTTPretty :)', cls.Response(method=method, uri=uri, **headers), ] - matcher = URIMatcher(uri, entries_for_this_uri, + matcher = URIMatcher(uri, expected_data, entries_for_this_uri, match_querystring) if matcher in cls._entries: matcher.entries.extend(cls._entries[matcher]) diff --git a/tests/functional/test_requests.py b/tests/functional/test_requests.py index 0a4bf55c..8ec84a21 100644 --- a/tests/functional/test_requests.py +++ b/tests/functional/test_requests.py @@ -649,6 +649,32 @@ def test_lack_of_trailing_slash(): @httprettified +def test_httpretty_should_check_post_payload(): + "HTTPretty should allow checking POST data payload" + + HTTPretty.register_uri( + HTTPretty.POST, + "https://api.imaginary.com/v1/sweet/", + expected_data={'name': "Lollipop"}, + body='{"id": 12, "status": "Created"}', + ) + + response = requests.post( + "https://api.imaginary.com/v1/sweet/", + {"name": "Lollipop"} + ) + + expect(HTTPretty.last_request.method).to.equal('POST') + expect(HTTPretty.last_request.method).to.equal('POST') + expect(HTTPretty.last_request.body).to.equal(b'name=Lollipop') + expect(response.json()).to.equal({"id": 12, "status": "Created"}) + + requests.post.when.called_with( + "https://api.imaginary.com/v1/sweet/", + {'wrong': 'data'} + ).should.throw(ValueError) + + def test_unicode_querystrings(): ("Querystrings should accept unicode characters") HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/login", diff --git a/tests/functional/test_urllib2.py b/tests/functional/test_urllib2.py index cb84f000..d341b1ae 100644 --- a/tests/functional/test_urllib2.py +++ b/tests/functional/test_urllib2.py @@ -27,6 +27,7 @@ from __future__ import unicode_literals try: + from urllib import urlencode from urllib.request import urlopen import urllib.request as urllib2 except ImportError: @@ -335,3 +336,47 @@ def test_httpretty_should_allow_registering_regexes(): fd.close() expect(got).to.equal(b"Found brand") + + +@httprettified +def test_httpretty_should_check_post_payload(): + "HTTPretty should allow checking POST data payload" + + HTTPretty.register_uri( + HTTPretty.POST, + "https://api.imaginary.com/v1/sweet/", + expected_data={'name': "Lollipop"}, + body='{"id": 12, "status": "Created"}', + ) + + request = urllib2.Request( + "https://api.imaginary.com/v1/sweet/", + urlencode({"name": "Lollipop"}), + { + 'content-type': 'text/json', + }, + ) + fd = urllib2.urlopen(request) + got = fd.read() + fd.close() + + expect(HTTPretty.last_request.method).to.equal('POST') + expect(HTTPretty.last_request.method).to.equal('POST') + expect(HTTPretty.last_request.body).to.equal(b'name=Lollipop') + expect(got).to.equal(b'{"id": 12, "status": "Created"}') + + request = urllib2.Request( + "https://api.imaginary.com/v1/sweet/", + urlencode({"wrong": "data"}), + { + 'content-type': 'text/json', + }, + ) + + try: + fd = urllib2.urlopen(request) + got = fd.read() + fd.close() + raise Exception("Payload checked didn't work") + except ValueError: + pass