Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #3160 -- Added the ability to control the content type in a tes…

…t client POST request. This is to allow easier testing of json-rpc/xml-rpc/soap etc interfaces. Thanks to Mikeal Rogers for the suggestion, and Ben <afternoon@uk2.net> for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4529 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit d6d51c9546a8734683c75bddc2cab93e05247f1e 1 parent 4a85a75
@freakboy3742 freakboy3742 authored
View
18 django/test/client.py
@@ -9,6 +9,9 @@
from django.test import signals
from django.utils.functional import curry
+BOUNDARY = 'BoUnDaRyStRiNg'
+MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
+
class ClientHandler(BaseHandler):
"""
A HTTP Handler that can be used for testing purposes.
@@ -184,19 +187,20 @@ def get(self, path, data={}, **extra):
return self.request(**r)
- def post(self, path, data={}, **extra):
+ def post(self, path, data={}, content_type=MULTIPART_CONTENT, **extra):
"Request a response from the server using POST."
- BOUNDARY = 'BoUnDaRyStRiNg'
+ if content_type is MULTIPART_CONTENT:
+ post_data = encode_multipart(BOUNDARY, data)
+ else:
+ post_data = data
- encoded = encode_multipart(BOUNDARY, data)
- stream = StringIO(encoded)
r = {
- 'CONTENT_LENGTH': len(encoded),
- 'CONTENT_TYPE': 'multipart/form-data; boundary=%s' % BOUNDARY,
+ 'CONTENT_LENGTH': len(post_data),
+ 'CONTENT_TYPE': content_type,
'PATH_INFO': path,
'REQUEST_METHOD': 'POST',
- 'wsgi.input': stream,
+ 'wsgi.input': StringIO(post_data),
}
r.update(extra)
View
20 docs/testing.txt
@@ -217,15 +217,21 @@ can be invoked on the ``Client`` instance.
http://yoursite.com/customers/details/?name=fred&age=7
-``post(path, data={})``
- Make a POST request on the provided ``path``. The key-value pairs in the
- data dictionary will be used to create the POST data payload. This payload
- will be transmitted with the mimetype ``multipart/form-data``.
-
- However submitting files is a special case. To POST a file, you need only
+``post(path, data={}, content_type=MULTIPART_CONTENT)``
+ Make a POST request on the provided ``path``. If you provide a content type
+ (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be
+ sent as-is in the POST request, using the content type in the HTTP
+ ``Content-Type`` header.
+
+ If you do not provide a value for ``content_type``, the values in
+ ``data`` will be transmitted with a content type of ``multipart/form-data``.
+ The key-value pairs in the data dictionary will be encoded as a multipart
+ message and used to create the POST data payload.
+
+ Submitting files is a special case. To POST a file, you need only
provide the file field name as a key, and a file handle to the file you wish to
upload as a value. The Test Client will populate the two POST fields (i.e.,
- ``field`` and ``field_file``) required by FileField. For example::
+ ``field`` and ``field_file``) required by Django's FileField. For example::
c = Client()
f = open('wishlist.doc')
View
12 tests/modeltests/test_client/models.py
@@ -43,7 +43,7 @@ def test_get_post_view(self):
# Check some response details
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, 'Empty POST Template')
+ self.assertEqual(response.template.name, 'Empty GET Template')
def test_empty_post(self):
"POST an empty dictionary to a view"
@@ -53,7 +53,7 @@ def test_empty_post(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, 'Empty POST Template')
- def test_post_view(self):
+ def test_post(self):
"POST some data to a view"
post_data = {
'value': 37
@@ -66,6 +66,14 @@ def test_post_view(self):
self.assertEqual(response.template.name, 'POST Template')
self.failUnless('Data received' in response.content)
+ def test_raw_post(self):
+ test_doc = """<?xml version="1.0" encoding="utf-8"?><library><book><title>Blink</title><author>Malcolm Gladwell</author></book></library>"""
+ response = self.client.post("/test_client/raw_post_view/", test_doc,
+ content_type="text/xml")
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.template.name, "Book template")
+ self.assertEqual(response.content, "Blink - Malcolm Gladwell")
+
def test_redirect(self):
"GET a URL that redirects elsewhere"
response = self.client.get('/test_client/redirect_view/')
View
1  tests/modeltests/test_client/urls.py
@@ -4,6 +4,7 @@
urlpatterns = patterns('',
(r'^get_view/$', views.get_view),
(r'^post_view/$', views.post_view),
+ (r'^raw_post_view/$', views.raw_post_view),
(r'^redirect_view/$', views.redirect_view),
(r'^login_protected_view/$', views.login_protected_view),
(r'^session_view/$', views.session_view),
View
30 tests/modeltests/test_client/views.py
@@ -1,3 +1,4 @@
+from xml.dom.minidom import parseString
from django.template import Context, Template
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
@@ -13,15 +14,34 @@ def post_view(request):
"""A view that expects a POST, and returns a different template depending
on whether any POST data is available
"""
- if request.POST:
- t = Template('Data received: {{ data }} is the value.', name='POST Template')
- c = Context({'data': request.POST['value']})
+ if request.method == 'POST':
+ if request.POST:
+ t = Template('Data received: {{ data }} is the value.', name='POST Template')
+ c = Context({'data': request.POST['value']})
+ else:
+ t = Template('Viewing POST page.', name='Empty POST Template')
+ c = Context()
else:
- t = Template('Viewing POST page.', name='Empty POST Template')
+ t = Template('Viewing GET page.', name='Empty GET Template')
c = Context()
-
+
return HttpResponse(t.render(c))
+def raw_post_view(request):
+ """A view which expects raw XML to be posted and returns content extracted
+ from the XML"""
+ if request.method == 'POST':
+ root = parseString(request.raw_post_data)
+ first_book = root.firstChild.firstChild
+ title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
+ t = Template("{{ title }} - {{ author }}", name="Book template")
+ c = Context({"title": title, "author": author})
+ else:
+ t = Template("GET request.", name="Book GET template")
+ c = Context()
+
+ return HttpResponse(t.render(c))
+
def redirect_view(request):
"A view that redirects all requests to the GET view"
return HttpResponseRedirect('/test_client/get_view/')
Please sign in to comment.
Something went wrong with that request. Please try again.