Browse Source

Fixed #20919 -- Extended assertRedirects to be able to avoid fetching redirect's response.

Thanks mjtamlyn for the suggestion.
Juan Catalano 11 years ago
parent
commit
4840fd9cbc

+ 12 - 9
django/test/testcases.py

@@ -225,12 +225,14 @@ class SimpleTestCase(unittest.TestCase):
         return override_settings(**kwargs)
         return override_settings(**kwargs)
 
 
     def assertRedirects(self, response, expected_url, status_code=302,
     def assertRedirects(self, response, expected_url, status_code=302,
-                        target_status_code=200, host=None, msg_prefix=''):
+                        target_status_code=200, host=None, msg_prefix='',
+                        fetch_redirect_response=True):
         """Asserts that a response redirected to a specific URL, and that the
         """Asserts that a response redirected to a specific URL, and that the
         redirect URL can be loaded.
         redirect URL can be loaded.
 
 
         Note that assertRedirects won't work for external links since it uses
         Note that assertRedirects won't work for external links since it uses
-        TestClient to do a request.
+        TestClient to do a request (use fetch_redirect_response=False to check
+        such links without fetching thtem).
         """
         """
         if msg_prefix:
         if msg_prefix:
             msg_prefix += ": "
             msg_prefix += ": "
@@ -264,14 +266,15 @@ class SimpleTestCase(unittest.TestCase):
             url = response.url
             url = response.url
             scheme, netloc, path, query, fragment = urlsplit(url)
             scheme, netloc, path, query, fragment = urlsplit(url)
 
 
-            redirect_response = response.client.get(path, QueryDict(query))
+            if fetch_redirect_response:
+                redirect_response = response.client.get(path, QueryDict(query))
 
 
-            # Get the redirection page, using the same client that was used
-            # to obtain the original response.
-            self.assertEqual(redirect_response.status_code, target_status_code,
-                msg_prefix + "Couldn't retrieve redirection page '%s':"
-                " response code was %d (expected %d)" %
-                    (path, redirect_response.status_code, target_status_code))
+                # Get the redirection page, using the same client that was used
+                # to obtain the original response.
+                self.assertEqual(redirect_response.status_code, target_status_code,
+                    msg_prefix + "Couldn't retrieve redirection page '%s':"
+                    " response code was %d (expected %d)" %
+                        (path, redirect_response.status_code, target_status_code))
 
 
         e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(
         e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(
                                                               expected_url)
                                                               expected_url)

+ 5 - 0
docs/releases/1.7.txt

@@ -293,6 +293,11 @@ Tests
   :attr:`~django.test.runner.DiscoverRunner.test_runner`, which facilitate
   :attr:`~django.test.runner.DiscoverRunner.test_runner`, which facilitate
   overriding the way tests are collected and run.
   overriding the way tests are collected and run.
 
 
+* The ``fetch_redirect_response`` argument was added to
+  :meth:`~django.test.SimpleTestCase.assertRedirects`. Since the test
+  client can't fetch externals URLs, this allows you to use ``assertRedirects``
+  with redirects that aren't part of your Django app.
+
 Backwards incompatible changes in 1.7
 Backwards incompatible changes in 1.7
 =====================================
 =====================================
 
 

+ 7 - 1
docs/topics/testing/overview.txt

@@ -1542,7 +1542,7 @@ your test suite.
     You can use this as a context manager in the same way as
     You can use this as a context manager in the same way as
     :meth:`~SimpleTestCase.assertTemplateUsed`.
     :meth:`~SimpleTestCase.assertTemplateUsed`.
 
 
-.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
+.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)
 
 
     Asserts that the response return a ``status_code`` redirect status, it
     Asserts that the response return a ``status_code`` redirect status, it
     redirected to ``expected_url`` (including any GET data), and the final
     redirected to ``expected_url`` (including any GET data), and the final
@@ -1552,6 +1552,12 @@ your test suite.
     ``target_status_code`` will be the url and status code for the final
     ``target_status_code`` will be the url and status code for the final
     point of the redirect chain.
     point of the redirect chain.
 
 
+    .. versionadded:: 1.7
+
+    If ``fetch_redirect_response`` is ``False``, the final page won't be
+    loaded. Since the test client can't fetch externals URLs, this is
+    particularly useful if ``expected_url`` isn't part of your Django app.
+
 .. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)
 .. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)
 
 
     Asserts that the strings ``html1`` and ``html2`` are equal. The comparison
     Asserts that the strings ``html1`` and ``html2`` are equal. The comparison

+ 4 - 0
tests/test_client/tests.py

@@ -405,6 +405,10 @@ class ClientTest(TestCase):
 
 
         # TODO: Log in with right permissions and request the page again
         # TODO: Log in with right permissions and request the page again
 
 
+    def test_external_redirect(self):
+        response = self.client.get('/test_client/django_project_redirect/')
+        self.assertRedirects(response, 'https://www.djangoproject.com/', fetch_redirect_response=False)
+
     def test_session_modifying_view(self):
     def test_session_modifying_view(self):
         "Request a page that modifies the session"
         "Request a page that modifies the session"
         # Session value isn't set initially
         # Session value isn't set initially

+ 2 - 1
tests/test_client/urls.py

@@ -29,5 +29,6 @@ urlpatterns = patterns('',
     (r'^session_view/$', views.session_view),
     (r'^session_view/$', views.session_view),
     (r'^broken_view/$', views.broken_view),
     (r'^broken_view/$', views.broken_view),
     (r'^mail_sending_view/$', views.mail_sending_view),
     (r'^mail_sending_view/$', views.mail_sending_view),
-    (r'^mass_mail_sending_view/$', views.mass_mail_sending_view)
+    (r'^mass_mail_sending_view/$', views.mass_mail_sending_view),
+    (r'^django_project_redirect/$', views.django_project_redirect),
 )
 )

+ 3 - 0
tests/test_client/views.py

@@ -257,3 +257,6 @@ def mass_mail_sending_view(request):
     c.send_messages([m1,m2])
     c.send_messages([m1,m2])
 
 
     return HttpResponse("Mail sent")
     return HttpResponse("Mail sent")
+
+def django_project_redirect(request):
+    return HttpResponseRedirect('https://www.djangoproject.com/')