Testing Exception Rendering in Django

“A macro shot of a Macbook Pro screen with a few dozen lines of code” by Luca Bravo on Unsplash

Have you ever encountered an exception while processing another exception? If no, you are lucky. In this short post, you’ll learn how to make sure that this will never happen (again).


When an exception happens, Django can handle it in different ways:

  • Show your custom 500 page
  • Send an Email to the admins
  • Send a Error Report to Sentry or another Log Aggregation Tool

All those handlers could throw an exception itself. Those exceptions have ugly Tracebacks and often only occur in production. So better make sure that exception handling is working right.

A simple test

Usually, Django uses django.views.debug.ExceptionReporter to collect all information (like the content of settings.py).

For this to test, you need to have a view that always throws an exception. This may look strange at the beginning but may be handy for other purposes as well (e.g. to check if sentry is working fine):

# urls.py
# Always throws exception
urlpatterns += [
url(r'^exception/$', views.exception_view, name='exception'),
]
# views.py
class TestException(Exception):
pass
def exception_view(request):
try:
raise TestException("This is a exception that is raised "
"when opening /exception/. "
"It can be used in tests.")
except TestException:
type, value, tb = sys.exc_info()

# Simulate detailed error reporting.
# Sometimes this throws an exception itself.
# Then the test test_exception_rendering() will fail.

reporter = ExceptionReporter(request, type, value, tb)
reporter.get_traceback_text()

raise

And now let’s test if the view works like expected:

# test.py
def test_exception_rendering(self):
logging.disable(logging.CRITICAL) # Don't log exceptions

try:
self.client.get("/exception/")
except TestException:
logging.disable(logging.NOTSET) # Enable logging again
return
except
Exception:
pass
logging.disable(logging.NOTSET) # Enable logging again
    self.fail("Exception Rendering is not working. Try opening"
"/exception/. It should raise a TestException.")

Over & out.