diff --git a/django/test/testcases.py b/django/test/testcases.py index 153931f42a..fcf6ccec4d 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -56,32 +56,35 @@ class TestCase(unittest.TestCase): self._pre_setup() super(TestCase, self).run(result) - def assertRedirects(self, response, expected_path): - """Assert that a response redirected to a specific URL, and that the + def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200): + """Assert that a response redirected to a specific URL, and that the redirect URL can be loaded. """ - self.assertEqual(response.status_code, 302, - "Response didn't redirect: Reponse code was %d" % response.status_code) + self.assertEqual(response.status_code, status_code, + "Response didn't redirect: Reponse code was %d (expected %d)" % + (response.status_code, status_code)) scheme, netloc, path, params, query, fragment = urlparse(response['Location']) self.assertEqual(path, expected_path, "Response redirected to '%s', expected '%s'" % (path, expected_path)) redirect_response = self.client.get(path) - self.assertEqual(redirect_response.status_code, 200, - "Couldn't retrieve redirection page '%s'" % path) + self.assertEqual(redirect_response.status_code, target_status_code, + "Couldn't retrieve redirection page '%s': response code was %d (expected %d)" % + (path, response.status_code, status_code)) - def assertContains(self, response, text, count=1): + def assertContains(self, response, text, count=1, status_code=200): """Assert that a response indicates that a page was retreived successfully, - (i.e., the HTTP status code was 200), and that ``text`` occurs ``count`` + (i.e., the HTTP status code was as expected), and that ``text`` occurs ``count`` times in the content of the response. """ - self.assertEqual(response.status_code, 200, - "Couldn't retrieve page'") + self.assertEqual(response.status_code, status_code, + "Couldn't retrieve page: Response code was %d (expected %d)'" % + (response.status_code, status_code)) real_count = response.content.count(text) self.assertEqual(real_count, count, - "Could only find %d of %d instances of '%s' in response" % (real_count, count, text)) - + "Found %d instances of '%s' in response (expected %d)" % (real_count, text, count)) + def assertFormError(self, response, form, field, errors): "Assert that a form used to render the response has a specific field error" if not response.context: diff --git a/docs/testing.txt b/docs/testing.txt index ba13dab67e..b44b67c20a 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -472,9 +472,9 @@ Normal Python unit tests have a wide range of assertions, such as ``django.TestCase`` adds to these, providing some assertions that can be useful in testing the behavior of web sites. -``assertContains(response, text, count=1)`` - Assert that a response indicates that a page was retrieved successfully, - (i.e., the HTTP status code was 200), and that ``text`` occurs ``count`` +``assertContains(response, text, count=1, status_code=200)`` + Assert that a response indicates that a page could be retrieved and + produced the nominated status code, and that ``text`` occurs ``count`` times in the content of the response. ``assertFormError(response, form, field, errors)`` @@ -493,9 +493,10 @@ that can be useful in testing the behavior of web sites. Assert that the template with the given name was *not* used in rendering the response. -``assertRedirects(response, expected_path)`` - Assert that the response received redirects the browser to the provided - path, and that the expected_path can be retrieved. +``assertRedirects(response, expected_path, status_code=302, target_status_code=200)`` + Assert that the response received produced the nominated status code, + redirects the browser to the provided path, and that retrieving the provided + path yields a response with the target status code. ``assertTemplateUsed(response, template_name)`` Assert that the template with the given name was used in rendering the diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py index 34242ee0d8..c36b435e25 100644 --- a/tests/modeltests/test_client/models.py +++ b/tests/modeltests/test_client/models.py @@ -35,7 +35,7 @@ class ClientTest(TestCase): self.assertEqual(response.template.name, 'GET Template') def test_no_template_view(self): - "Check that template usage assersions work then templates aren't in use" + "Template usage assertions work then templates aren't in use" response = self.client.get('/test_client/no_template_view/') # Check that the no template case doesn't mess with the template assertions @@ -75,6 +75,7 @@ class ClientTest(TestCase): self.failUnless('Data received' in response.content) def test_raw_post(self): + "POST raw data (with a content type) to a view" test_doc = """BlinkMalcolm Gladwell""" response = self.client.post("/test_client/raw_post_view/", test_doc, content_type="text/xml") @@ -89,6 +90,28 @@ class ClientTest(TestCase): # Check that the response was a 302 (redirect) self.assertRedirects(response, '/test_client/get_view/') + def test_permanent_redirect(self): + "GET a URL that redirects permanently elsewhere" + response = self.client.get('/test_client/permanent_redirect_view/') + + # Check that the response was a 301 (permanent redirect) + self.assertRedirects(response, '/test_client/get_view/', status_code=301) + + def test_redirect_to_strange_location(self): + "GET a URL that redirects to a non-200 page" + response = self.client.get('/test_client/double_redirect_view/') + + # Check that the response was a 302, and that + # the attempt to get the redirection location returned 301 when retrieved + self.assertRedirects(response, '/test_client/permanent_redirect_view/', target_status_code=301) + + def test_notfound_response(self): + "GET a URL that responds as '404:Not Found'" + response = self.client.get('/test_client/bad_view/') + + # Check that the response was a 404, and that the content contains MAGIC + self.assertContains(response, 'MAGIC', status_code=404) + def test_valid_form(self): "POST valid data to a form" post_data = { diff --git a/tests/modeltests/test_client/urls.py b/tests/modeltests/test_client/urls.py index 52fc8fe692..12303403ed 100644 --- a/tests/modeltests/test_client/urls.py +++ b/tests/modeltests/test_client/urls.py @@ -1,4 +1,5 @@ from django.conf.urls.defaults import * +from django.views.generic.simple import redirect_to import views urlpatterns = patterns('', @@ -7,6 +8,9 @@ urlpatterns = patterns('', (r'^post_view/$', views.post_view), (r'^raw_post_view/$', views.raw_post_view), (r'^redirect_view/$', views.redirect_view), + (r'^permanent_redirect_view/$', redirect_to, { 'url': '/test_client/get_view/' }), + (r'^double_redirect_view/$', views.double_redirect_view), + (r'^bad_view/$', views.bad_view), (r'^form_view/$', views.form_view), (r'^form_view_with_template/$', views.form_view_with_template), (r'^login_protected_view/$', views.login_protected_view), diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py index 18d6a2dcd9..0320f0618a 100644 --- a/tests/modeltests/test_client/views.py +++ b/tests/modeltests/test_client/views.py @@ -1,7 +1,7 @@ from xml.dom.minidom import parseString from django.core.mail import EmailMessage, SMTPConnection from django.template import Context, Template -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound from django.contrib.auth.decorators import login_required from django.newforms.forms import Form from django.newforms import fields @@ -54,6 +54,14 @@ def redirect_view(request): "A view that redirects all requests to the GET view" return HttpResponseRedirect('/test_client/get_view/') +def double_redirect_view(request): + "A view that redirects all requests to a redirection view" + return HttpResponseRedirect('/test_client/permanent_redirect_view/') + +def bad_view(request): + "A view that returns a 404 with some error content" + return HttpResponseNotFound('Not found!. This page contains some MAGIC content') + TestChoices = ( ('a', 'First Choice'), ('b', 'Second Choice'),