I've the need to write some tests for custom handler404 and handler500 in Django, using django test dummy client. The first is easy to test while I have problems with the second.
Basically, problem is that Django test client does not catch the exception and does not route to the proper handler. This is a problem because we need to test that the right custom handler and template are used.
We have a simple middleware class to simulate exceptions for tests:
class HTTPStatusCodeMiddleware(object):
def process_view(self, request, *args):
if 'cookie_500_error' in request.COOKIES:
raise Exception('Test exception')
Code above works fine for manual testing in browser.
Now, tests are:
def test_404_template(self):
c = Client()
url = '/not_existing.html'
response = c.get(url)
self.assertEqual(response.status_code, 404) # success
self.assertTemplateUsed(response, 'custom/404.html') # success
def test_500_template(self):
c = Client()
c.cookies['cookie_500_error'] = '1'
response = c.get('/') # here middleware raises exception!!!
self.assertEqual(response.status_code, 500)
self.assertTemplateUsed(response, 'custom/500.html')
Any idea? I don't have the option to use selenium. Thanks!
Django test client handles only some exceptions (see the docs ). All the others are visible in the test and you can test them ;)
The new test Client
argument raise_request_exception
allows controlling whether or not exceptions raised during the request should also be raised in the test. The value defaults to True
for backwards compatibility. If it is False
and an exception occurs, the test client will return a 500 response with the attribute exc_info
, a tuple providing information of the exception that occurred.
c = Client(raise_request_exception=False)
For information at the documentation
For Django 2.x, the test client can be stopped from raising exceptions by patching its store_exc_info
method:
c = Client()
c.store_exc_info = lambda *args, **kw: None
response = c.get("/error")
assert response.status_code == 500
Assuming that the view handling the /error
url raises an exception, this would allow us to get the 500 Server Error
response.
For Django>=3.0, the raise_request_exception
parameter should be used, instead (as mentioned in @CesarCanassa answer)
So django test Client class doesn't catch exceptions by design, and this is a good thing.
Since the problem specifically was to test custom handler500, which is set by custom middleware on specific settings just by replacing request.urlconf variable with the custom urlconf module, the solution was to use RequestFactory to build the request, and test request.urlconf.handler500 view:
in custom/client1/urls.py
def handler500(request):
data = {'client', 'client1 is sorry!'}
ctx = RequestContext(request)
content = render_to_string('client1/500.html', data, ctx)
return http.HttpResponseServerError(content)
in tests/views/test_error_pages.py
def test_500_template(self):
req = RequestFactory().get('/')
req.user = AnonymousUser()
req.session = {}
cust_mw = CustomUrlconfMiddleware()
cust_mw.process_request(req) # set the custom request.urlconf
urlconf = importlib.import_module(req.urlconf)
response = urlconf.handler500(req)
self.assertEqual(response.status_code, 500)
assert_str = '/static/img/custom/client1/'
self.assertTrue(assert_str in response.content,
msg='500 template is not for client1. String {} is not in content'.format(assert_str))
Okay I just ran into a similar problem with using PermissionDenied
exceptions in my unit tests. Since Django doesn't catch them, it was causing my test to crash instead of fail. I did figure out an easy solution that I haven't seen posted yet and it's this:
Sample view:
from django.core.exceptions import PermissionDenied
class SampleView(object):
def setup(request):
if not request_is_authenticated(request):
raise PermissionDenied
Unit test:
from django.core.exceptions import PermissionDenied
def test_permission(self):
try:
SampleView.setup(request)
except PermissionDenied:
print('Hallelujah no crashing!')
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.