As docs says https://docs.djangoproject.com/en/2.2/topics/testing/tools/#exceptions;
The only exceptions that are not visible to the test client are
Http404,PermissionDenied,SystemExit, andSuspiciousOperation. Django catches these exceptions internally and converts them into the appropriate HTTP response codes. In these cases, you can checkresponse.status_codein your test.
I handle a custom a login mixin for raising an error to user logged in but has no access to that page.
class LoginQuizMarkerMixin(LoginRequiredMixin):
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated:
if not self.request.user.has_perm('quizzes.view_sittings'):
raise PermissionDenied("You don't have any access to this page.")
return super().dispatch(*args, **kwargs)
I my unitest, it working fine.
class TestQuestionMarking(TestCase):
def setUp(self):
self.c1 = Category.objects.create_category(name='elderberries')
self.student = User.objects.create_user(username='student',
email='student@rebels.com',
password='top_secret')
self.teacher = User.objects.create_user(username='teacher',
email='teacher@jedis.com',
password='use_d@_force')
self.teacher.user_permissions.add(Permission.objects.get(codename='view_sittings'))
....
def test_paper_marking_list_view(self):
# should be 302 (redirection)
marking_url = reverse('quizzes:quiz_marking')
response = self.client.get(marking_url)
print('response1', response)
# should be 403 (permission denied)
self.client.login(username='student', password='top_secret')
response = self.client.get(marking_url)
print('response2', response)
# should be 200 (allowed)
self.client.login(username='teacher', password='use_d@_force')
response = self.client.get(marking_url)
print('response3', response)
But for somehow, it the error of PermissionDenied it showed an error like this:
docker-compose -f local.yml run --rm django python manage.py test labs.tests.quizzes.test_views.TestQuestionMarking.test_paper_marking_list_view
response1 <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/accounts/login/?next=/quizzes/marking/">
WARNING 2021-02-04 00:28:44,270 log 1 139681767683904 [log.py:222] Forbidden (Permission denied): /quizzes/marking/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.8/contextlib.py", line 75, in inner
return func(*args, **kwds)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/app/my_app/quizzes/views.py", line 37, in dispatch
raise PermissionDenied("You don't have any access to this page.")
django.core.exceptions.PermissionDenied: You don't have any access to this page.
response2 <HttpResponseForbidden status_code=403, "text/html; charset=utf-8">
response3 <TemplateResponse status_code=200, "text/html; charset=utf-8">
And what I expected is still capured as an error, not showing up like above. And should be like this below:
response1 <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/accounts/login/?next=/quizzes/marking/">
response2 <HttpResponseForbidden status_code=403, "text/html; charset=utf-8">
response3 <TemplateResponse status_code=200, "text/html; charset=utf-8">
But, in another test when I try to change it with raise Http404, it worked fine:
class LoginQuizMarkerMixin(LoginRequiredMixin):
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated:
if not self.request.user.has_perm('quizzes.view_sittings'):
# raise PermissionDenied("You don't have any access to this page.")
raise Http404
return super().dispatch(*args, **kwargs)
The console output:
response1 <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/accounts/login/?next=/quizzes/marking/">
WARNING 2021-02-04 13:39:05,368 log 1 139683990402880 [log.py:222] Not Found: /quizzes/marking/
response2 <HttpResponseNotFound status_code=404, "text/html; charset=utf-8">
response3 <TemplateResponse status_code=200, "text/html; charset=utf-8">