diff --git a/AUTHORS b/AUTHORS index 7bbec38cf5..328c4a0fe4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -47,6 +47,7 @@ answer newbie questions, and generally made Django that much better: Niran Babalola Morten Bagai Mikaƫl Barbero + Scott Barr Jiri Barton Ned Batchelder batiste@dosimple.ch diff --git a/django/test/client.py b/django/test/client.py index 6a3401a2ff..0cb8db3f4e 100644 --- a/django/test/client.py +++ b/django/test/client.py @@ -284,6 +284,69 @@ class Client(object): return self.request(**r) + def head(self, path, data={}, **extra): + """ + Request a response from the server using HEAD. + """ + r = { + 'CONTENT_LENGTH': None, + 'CONTENT_TYPE': 'text/html; charset=utf-8', + 'PATH_INFO': urllib.unquote(path), + 'QUERY_STRING': urlencode(data, doseq=True), + 'REQUEST_METHOD': 'HEAD', + } + r.update(extra) + + return self.request(**r) + + def options(self, path, data={}, **extra): + """ + Request a response from the server using OPTIONS. + """ + r = { + 'CONTENT_LENGTH': None, + 'CONTENT_TYPE': None, + 'PATH_INFO': urllib.unquote(path), + 'QUERY_STRING': urlencode(data, doseq=True), + 'REQUEST_METHOD': 'OPTIONS', + } + r.update(extra) + + return self.request(**r) + + def put(self, path, data={}, content_type=MULTIPART_CONTENT, **extra): + """ + Send a resource to the server using PUT. + """ + if content_type is MULTIPART_CONTENT: + post_data = encode_multipart(BOUNDARY, data) + else: + post_data = data + r = { + 'CONTENT_LENGTH': len(post_data), + 'CONTENT_TYPE': content_type, + 'PATH_INFO': urllib.unquote(path), + 'REQUEST_METHOD': 'PUT', + 'wsgi.input': FakePayload(post_data), + } + r.update(extra) + + return self.request(**r) + + def delete(self, path, data={}, **extra): + """ + Send a DELETE request to the server. + """ + r = { + 'CONTENT_LENGTH': None, + 'CONTENT_TYPE': None, + 'PATH_INFO': urllib.unquote(path), + 'REQUEST_METHOD': 'DELETE', + } + r.update(extra) + + return self.request(**r) + def login(self, **credentials): """ Sets the Client to appear as if it has successfully logged into a site. diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index 4f37b3bdc0..540900acf6 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -544,6 +544,36 @@ arguments at time of construction: Note that you should manually close the file after it has been provided to ``post()``. + .. method:: Client.head(path, data={}) + + .. versionadded:: development + + Makes a HEAD request on the provided ``path`` and returns a ``Response`` + object. Useful for testing RESTful interfaces. Acts just like + :meth:`Client.get` except it does not return a message body. + + .. method:: Client.options(path, data={}) + + .. versionadded:: development + + Makes an OPTIONS request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. + + .. method:: Client.put(path, data={}, content_type=MULTIPART_CONTENT) + + .. versionadded:: development + + Makes an PUT request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. Acts just + like :meth:`Client.put` except with the PUT request method. + + .. method:: Client.delete(path) + + .. versionadded:: development + + Makes an DELETE request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. + .. method:: Client.login(**credentials) .. versionadded:: 1.0 diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py index 1bffc7d225..5a3489040a 100644 --- a/tests/regressiontests/test_client_regress/models.py +++ b/tests/regressiontests/test_client_regress/models.py @@ -382,4 +382,42 @@ class SessionTests(TestCase): response = self.client.get('/test_client_regress/check_session/') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'YES') - \ No newline at end of file + +class RequestMethodTests(TestCase): + def test_get(self): + "Request a view via request method GET" + response = self.client.get('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'request method: GET') + + def test_post(self): + "Request a view via request method POST" + response = self.client.post('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'request method: POST') + + def test_head(self): + "Request a view via request method HEAD" + response = self.client.head('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + # A HEAD request doesn't return any content. + self.assertNotEqual(response.content, 'request method: HEAD') + self.assertEqual(response.content, '') + + def test_options(self): + "Request a view via request method OPTIONS" + response = self.client.options('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'request method: OPTIONS') + + def test_put(self): + "Request a view via request method PUT" + response = self.client.put('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'request method: PUT') + + def test_delete(self): + "Request a view via request method DELETE" + response = self.client.delete('/test_client_regress/request_methods/') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'request method: DELETE') diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py index ca21e18817..016a95170e 100644 --- a/tests/regressiontests/test_client_regress/urls.py +++ b/tests/regressiontests/test_client_regress/urls.py @@ -9,4 +9,5 @@ urlpatterns = patterns('', (r'^login_protected_redirect_view/$', views.login_protected_redirect_view), (r'^set_session/$', views.set_session_view), (r'^check_session/$', views.check_session_view), + (r'^request_methods/$', views.request_methods_view), ) diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py index 9cd786d86b..b3e5499d98 100644 --- a/tests/regressiontests/test_client_regress/views.py +++ b/tests/regressiontests/test_client_regress/views.py @@ -43,3 +43,7 @@ def set_session_view(request): def check_session_view(request): "A view that reads a session variable" return HttpResponse(request.session.get('session_var', 'NO')) + +def request_methods_view(request): + "A view that responds with the request method" + return HttpResponse('request method: %s' % request.method) \ No newline at end of file