Ticket #3162: text_client_exception_raise_v2.patch

File text_client_exception_raise_v2.patch, 5.4 KB (added by afternoon@…, 9 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
Back to Top