I am using Django for a project and is already in production.
In the production environment 500.html is rendered whenever a server error occurs.
How do I tes
How i do and test custom error handlers
Define custom View
based on TemplateView
# views.py
from django.views.generic import TemplateView
class ErrorHandler(TemplateView):
""" Render error template """
error_code = 404
template_name = 'index/error.html'
def dispatch(self, request, *args, **kwargs):
""" For error on any methods return just GET """
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['error_code'] = self.error_code
return context
def render_to_response(self, context, **response_kwargs):
""" Return correct status code """
response_kwargs = response_kwargs or {}
response_kwargs.update(status=self.error_code)
return super().render_to_response(context, **response_kwargs)
Tell django to use custom error handlers
# urls.py
from index.views import ErrorHandler
# error handing handlers - fly binding
for code in (400, 403, 404, 500):
vars()['handler{}'.format(code)] = ErrorHandler.as_view(error_code=code)
Testcase for custom error handlers
# tests.py
from unittest import mock
from django.test import TestCase
from django.core.exceptions import SuspiciousOperation, PermissionDenied
from django.http import Http404
from index import views
class ErrorHandlersTestCase(TestCase):
""" Check is correct error handlers work """
def raise_(exception):
def wrapped(*args, **kwargs):
raise exception('Test exception')
return wrapped
def test_index_page(self):
""" Should check is 200 on index page """
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'index/index.html')
@mock.patch('index.views.IndexView.get', raise_(Http404))
def test_404_page(self):
""" Should check is 404 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 404)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('404 Page not found', response.content.decode('utf-8'))
@mock.patch('index.views.IndexView.get', views.ErrorHandler.as_view(error_code=500))
def test_500_page(self):
""" Should check is 500 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 500)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('500 Server Error', response.content.decode('utf-8'))
@mock.patch('index.views.IndexView.get', raise_(SuspiciousOperation))
def test_400_page(self):
""" Should check is 400 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 400)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('400 Bad request', response.content.decode('utf-8'))
@mock.patch('index.views.IndexView.get', raise_(PermissionDenied))
def test_403_page(self):
""" Should check is 403 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('403 Permission Denied', response.content.decode('utf-8'))
You can simply define the handler404
and handler500
for errors in your main views.py
file as detailed in this answer:
https://stackoverflow.com/a/18009660/1913888
This will return the error that you desire when Django routes to that handler. No custom URL configuration is needed to route to a different URL name.
Are both debug settings false?
settings.DEBUG = False
settings.TEMPLATE_DEBUG = False
I prefer not to turn DEBUG off. Instead I put the following snippet in the urls.py:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^500/$', 'your_custom_view_if_you_wrote_one'),
(r'^404/$', 'django.views.generic.simple.direct_to_template', {'template': '404.html'}),
)
In the snippet above, the error page uses a custom view, you can easily replace it with Django's direct_to_template view though.
Now you can test 500 and 404 pages by calling their urls: http://example.com/500 and http://example.com/404