Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3162 -- Added coded to catch and rethrow exceptions that are t…

…hrown by the views visited by the test client. Thanks, Ben <afternoon@uk2.net>.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4482 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f9cdde0cb41851e9d1eb70bd108debb75f267585 1 parent 23272de
Russell Keith-Magee authored February 11, 2007
1  AUTHORS
@@ -53,6 +53,7 @@ answer newbie questions, and generally made Django that much better:
53 53
     Shannon -jj Behrens <http://jjinux.blogspot.com/>
54 54
     Esdras Beleza <linux@esdrasbeleza.com>
55 55
     James Bennett
  56
+    Ben <afternoon@uk2.net>
56 57
     Paul Bissex <http://e-scribe.com/>
57 58
     Simon Blanchard
58 59
     Andrew Brehaut <http://brehaut.net/blog>
1  django/contrib/auth/forms.py
@@ -4,6 +4,7 @@
4 4
 from django.template import Context, loader
5 5
 from django.core import validators
6 6
 from django import oldforms
  7
+from django.utils.translation import gettext as _
7 8
 
8 9
 class UserCreationForm(oldforms.Manipulator):
9 10
     "A form that creates a user, with no privileges, from the given username and password."
18  django/test/client.py
... ...
@@ -1,7 +1,9 @@
  1
+import sys
1 2
 from cStringIO import StringIO
2 3
 from django.conf import settings
3 4
 from django.core.handlers.base import BaseHandler
4 5
 from django.core.handlers.wsgi import WSGIRequest
  6
+from django.core.signals import got_request_exception
5 7
 from django.dispatch import dispatcher
6 8
 from django.http import urlencode, SimpleCookie
7 9
 from django.test import signals
@@ -100,6 +102,14 @@ def __init__(self, **defaults):
100 102
         self.defaults = defaults
101 103
         self.cookies = SimpleCookie()
102 104
         self.session = {}
  105
+        self.exc_info = None
  106
+        
  107
+    def store_exc_info(self, *args, **kwargs):
  108
+        """
  109
+        Utility method that can be used to store exceptions when they are
  110
+        generated by a view.
  111
+        """
  112
+        self.exc_info = sys.exc_info()
103 113
 
104 114
     def request(self, **request):
105 115
         """
@@ -128,6 +138,9 @@ def request(self, **request):
128 138
         on_template_render = curry(store_rendered_templates, data)
129 139
         dispatcher.connect(on_template_render, signal=signals.template_rendered)
130 140
 
  141
+        # Capture exceptions created by the handler
  142
+        dispatcher.connect(self.store_exc_info, signal=got_request_exception)
  143
+
131 144
         response = self.handler(environ)
132 145
 
133 146
         # Add any rendered template detail to the response
@@ -142,6 +155,11 @@ def request(self, **request):
142 155
             else:
143 156
                 setattr(response, detail, None)
144 157
 
  158
+        # Look for a signalled exception and reraise it
  159
+        if self.exc_info:
  160
+            raise self.exc_info[1], None, self.exc_info[2]
  161
+        
  162
+        # Update persistent cookie and session data
145 163
         if response.cookies:
146 164
             self.cookies.update(response.cookies)
147 165
 
11  docs/testing.txt
@@ -291,6 +291,17 @@ for testing purposes:
291 291
 
292 292
 .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
293 293
 
  294
+Exceptions
  295
+~~~~~~~~~~
  296
+
  297
+If you point the Test Client at a view that raises an exception, that exception
  298
+will be visible in the test case. You can then use a standard ``try...catch`` 
  299
+block, or ``unittest.TestCase.assertRaises()`` to test for exceptions.
  300
+
  301
+The only exceptions that are not visible in a Test Case are ``Http404``, 
  302
+``PermissionDenied`` and ``SystemExit``. Django catches these exceptions 
  303
+internally and converts them into the appropriate HTTP responses codes.
  304
+
294 305
 Persistent state
295 306
 ~~~~~~~~~~~~~~~~
296 307
 
12  tests/modeltests/test_client/models.py
@@ -114,4 +114,14 @@ def test_session_modifying_view(self):
114 114
         
115 115
         # Check that the session was modified
116 116
         self.assertEquals(self.client.session['tobacconist'], 'hovercraft')
117  
-        
  117
+
  118
+    def test_view_with_exception(self):
  119
+        "Request a page that is known to throw an error"
  120
+        self.assertRaises(KeyError, self.client.get, "/test_client/broken_view/")
  121
+        
  122
+        #Try the same assertion, a different way
  123
+        try:
  124
+            self.client.get('/test_client/broken_view/')
  125
+            self.fail('Should raise an error')
  126
+        except KeyError:
  127
+            pass
3  tests/modeltests/test_client/urls.py
@@ -6,5 +6,6 @@
6 6
     (r'^post_view/$', views.post_view),
7 7
     (r'^redirect_view/$', views.redirect_view),
8 8
     (r'^login_protected_view/$', views.login_protected_view),
9  
-    (r'^session_view/$', views.session_view)
  9
+    (r'^session_view/$', views.session_view),
  10
+    (r'^broken_view/$', views.broken_view)
10 11
 )
6  tests/modeltests/test_client/views.py
@@ -36,11 +36,13 @@ def login_protected_view(request):
36 36
 
37 37
 def session_view(request):
38 38
     "A view that modifies the session"
39  
-    
40 39
     request.session['tobacconist'] = 'hovercraft'
41 40
     
42 41
     t = Template('This is a view that modifies the session.', 
43 42
                  name='Session Modifying View Template')
44 43
     c = Context()
45 44
     return HttpResponse(t.render(c))
46  
-    
  45
+
  46
+def broken_view(request):
  47
+    """A view which just raises an exception, simulating a broken view."""
  48
+    raise KeyError("Oops! Looks like you wrote some bad code.")

0 notes on commit f9cdde0

Please sign in to comment.
Something went wrong with that request. Please try again.