Code

Ticket #3162: text_client_exception_raise_v2.patch

File text_client_exception_raise_v2.patch, 5.4 KB (added by afternoon@…, 8 years ago)

[patch] Reraise exceptions created during request handling so test cases may inspect them, added test and docs

  • django/test/client.py

     
    11from cStringIO import StringIO 
     2import sys 
    23from django.core.handlers.base import BaseHandler 
    34from django.core.handlers.wsgi import WSGIRequest 
     5from django.core.signals import got_request_exception 
    46from django.dispatch import dispatcher 
    57from django.http import urlencode, SimpleCookie 
    68from django.test import signals 
     
    98100        self.handler = ClientHandler() 
    99101        self.defaults = defaults 
    100102        self.cookie = SimpleCookie() 
     103        self.exc_info = None 
    101104 
    102105    def request(self, **request): 
    103106        """ 
     
    106109        Assumes defaults for the query environment, which can be overridden 
    107110        using the arguments to the request. 
    108111        """ 
     112        self.exc_info = None 
    109113 
    110114        environ = { 
    111115            'HTTP_COOKIE':      self.cookie, 
     
    126130        on_template_render = curry(store_rendered_templates, data) 
    127131        dispatcher.connect(on_template_render, signal=signals.template_rendered) 
    128132 
     133        # Capture exceptions created by the handler 
     134        dispatcher.connect(self.store_exc_info, signal=got_request_exception) 
     135 
    129136        response = self.handler(environ) 
    130137 
    131138        # Add any rendered template detail to the response 
     
    143150        if response.cookies: 
    144151            self.cookie.update(response.cookies) 
    145152 
     153        # Look for a signalled exception and reraise it 
     154        if self.exc_info: 
     155            raise self.exc_info[1], None, self.exc_info[2] 
     156 
    146157        return response 
    147158 
    148159    def get(self, path, data={}, **extra): 
     
    214241 
    215242        # Since we are logged in, request the actual page again 
    216243        return self.get(path) 
     244 
     245    def store_exc_info(self, *args, **kwargs): 
     246        self.exc_info = sys.exc_info() 
  • django/core/handlers/base.py

     
    103103        except SystemExit: 
    104104            pass # See http://code.djangoproject.com/ticket/1023 
    105105        except: # Handle everything else, including SuspiciousOperation, etc. 
     106            receivers = dispatcher.send(signal=signals.got_request_exception) 
    106107            if settings.DEBUG: 
    107108                from django.views import debug 
    108109                return debug.technical_500_response(request, *sys.exc_info()) 
    109110            else: 
    110111                # Get the exception info now, in case another exception is thrown later. 
    111112                exc_info = sys.exc_info() 
    112                 receivers = dispatcher.send(signal=signals.got_request_exception) 
    113113                # When DEBUG is False, send an error message to the admins. 
    114114                subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path) 
    115115                try: 
  • tests/modeltests/test_client/views.py

     
    3349    c = Context({'user': request.user}) 
    3450     
    3551    return HttpResponse(t.render(c)) 
     52 
     53def broken_view(request): 
     54    """A view which just raises an exception, simulating a broken view.""" 
     55    raise KeyError("Oops! Looks like you wrote some bad code.") 
  • tests/modeltests/test_client/models.py

     
    99107 
    100108        response = self.client.login('/test_client/login_protected_view/', 'otheruser', 'nopassword') 
    101109        self.assertFalse(response) 
     110 
     111    def test_view_with_exception(self): 
     112        self.assertRaises(KeyError, self.client.get, "/test_client/broken_view/") 
  • tests/modeltests/test_client/urls.py

     
    66    (r'^post_view/$', views.post_view), 
    77    (r'^redirect_view/$', views.redirect_view), 
    88    (r'^login_protected_view/$', views.login_protected_view), 
     9    (r'^broken_view/$', views.broken_view), 
    910) 
  • docs/testing.txt

     
    314324            # Check that the rendered context contains 5 customers 
    315325            self.failUnlessEqual(len(response.context['customers']), 5) 
    316326 
     327Exceptions 
     328---------- 
     329 
     330Exceptions raised by views or other code while handling a request made by 
     331``Client`` will bubble up to your test case. The default test runner, 
     332``django.test.simple.run_tests`` will print a stack trace for an unhandled 
     333exception. ``unittest.TestCase``'s ``assertRaises`` method can be used to test 
     334that exceptions are raised by views, which can be useful to test error 
     335handling. You may also catch exceptions in the normal way and inspect them in 
     336your test code. 
     337 
     338``Http404``, ``PermissionDenied`` and ``SystemExit`` are caught by Django's 
     339base handler. These exceptions will not make it back to your test if raised 
     340during a request. 
     341 
    317342Fixtures 
    318343-------- 
    319344