Fixed #3162 -- Added coded to catch and rethrow exceptions that are thrown 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
This commit is contained in:
Russell Keith-Magee 2007-02-11 00:23:31 +00:00
parent 23272de5db
commit f9cdde0cb4
7 changed files with 48 additions and 4 deletions

View File

@ -53,6 +53,7 @@ answer newbie questions, and generally made Django that much better:
Shannon -jj Behrens <http://jjinux.blogspot.com/> Shannon -jj Behrens <http://jjinux.blogspot.com/>
Esdras Beleza <linux@esdrasbeleza.com> Esdras Beleza <linux@esdrasbeleza.com>
James Bennett James Bennett
Ben <afternoon@uk2.net>
Paul Bissex <http://e-scribe.com/> Paul Bissex <http://e-scribe.com/>
Simon Blanchard Simon Blanchard
Andrew Brehaut <http://brehaut.net/blog> Andrew Brehaut <http://brehaut.net/blog>

View File

@ -4,6 +4,7 @@ from django.contrib.sites.models import Site
from django.template import Context, loader from django.template import Context, loader
from django.core import validators from django.core import validators
from django import oldforms from django import oldforms
from django.utils.translation import gettext as _
class UserCreationForm(oldforms.Manipulator): class UserCreationForm(oldforms.Manipulator):
"A form that creates a user, with no privileges, from the given username and password." "A form that creates a user, with no privileges, from the given username and password."

View File

@ -1,7 +1,9 @@
import sys
from cStringIO import StringIO from cStringIO import StringIO
from django.conf import settings from django.conf import settings
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.wsgi import WSGIRequest
from django.core.signals import got_request_exception
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.http import urlencode, SimpleCookie from django.http import urlencode, SimpleCookie
from django.test import signals from django.test import signals
@ -100,6 +102,14 @@ class Client:
self.defaults = defaults self.defaults = defaults
self.cookies = SimpleCookie() self.cookies = SimpleCookie()
self.session = {} self.session = {}
self.exc_info = None
def store_exc_info(self, *args, **kwargs):
"""
Utility method that can be used to store exceptions when they are
generated by a view.
"""
self.exc_info = sys.exc_info()
def request(self, **request): def request(self, **request):
""" """
@ -128,6 +138,9 @@ class Client:
on_template_render = curry(store_rendered_templates, data) on_template_render = curry(store_rendered_templates, data)
dispatcher.connect(on_template_render, signal=signals.template_rendered) dispatcher.connect(on_template_render, signal=signals.template_rendered)
# Capture exceptions created by the handler
dispatcher.connect(self.store_exc_info, signal=got_request_exception)
response = self.handler(environ) response = self.handler(environ)
# Add any rendered template detail to the response # Add any rendered template detail to the response
@ -142,6 +155,11 @@ class Client:
else: else:
setattr(response, detail, None) setattr(response, detail, None)
# Look for a signalled exception and reraise it
if self.exc_info:
raise self.exc_info[1], None, self.exc_info[2]
# Update persistent cookie and session data
if response.cookies: if response.cookies:
self.cookies.update(response.cookies) self.cookies.update(response.cookies)

View File

@ -291,6 +291,17 @@ for testing purposes:
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Exceptions
~~~~~~~~~~
If you point the Test Client at a view that raises an exception, that exception
will be visible in the test case. You can then use a standard ``try...catch``
block, or ``unittest.TestCase.assertRaises()`` to test for exceptions.
The only exceptions that are not visible in a Test Case are ``Http404``,
``PermissionDenied`` and ``SystemExit``. Django catches these exceptions
internally and converts them into the appropriate HTTP responses codes.
Persistent state Persistent state
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

View File

@ -114,4 +114,14 @@ class ClientTest(unittest.TestCase):
# Check that the session was modified # Check that the session was modified
self.assertEquals(self.client.session['tobacconist'], 'hovercraft') self.assertEquals(self.client.session['tobacconist'], 'hovercraft')
def test_view_with_exception(self):
"Request a page that is known to throw an error"
self.assertRaises(KeyError, self.client.get, "/test_client/broken_view/")
#Try the same assertion, a different way
try:
self.client.get('/test_client/broken_view/')
self.fail('Should raise an error')
except KeyError:
pass

View File

@ -6,5 +6,6 @@ urlpatterns = patterns('',
(r'^post_view/$', views.post_view), (r'^post_view/$', views.post_view),
(r'^redirect_view/$', views.redirect_view), (r'^redirect_view/$', views.redirect_view),
(r'^login_protected_view/$', views.login_protected_view), (r'^login_protected_view/$', views.login_protected_view),
(r'^session_view/$', views.session_view) (r'^session_view/$', views.session_view),
(r'^broken_view/$', views.broken_view)
) )

View File

@ -36,11 +36,13 @@ login_protected_view = login_required(login_protected_view)
def session_view(request): def session_view(request):
"A view that modifies the session" "A view that modifies the session"
request.session['tobacconist'] = 'hovercraft' request.session['tobacconist'] = 'hovercraft'
t = Template('This is a view that modifies the session.', t = Template('This is a view that modifies the session.',
name='Session Modifying View Template') name='Session Modifying View Template')
c = Context() c = Context()
return HttpResponse(t.render(c)) return HttpResponse(t.render(c))
def broken_view(request):
"""A view which just raises an exception, simulating a broken view."""
raise KeyError("Oops! Looks like you wrote some bad code.")