如何在(django)开发环境中测试500.html?

时间:2010-04-29 19:00:42

标签: django development-environment

我正在使用Django进行项目,并且已经投入使用。

在生产环境中,只要发生服务器错误,就会呈现500.html。

如何在开发环境中测试500.html的渲染?或者我如何在开发中渲染500.html,如果我关闭调试我仍然会得到错误而不是500.html

背景:我包含一些基于页面的页面元素,有些在调用500.html时丢失,并且想要在开发环境中调试它。

11 个答案:

答案 0 :(得分:47)

我不想关闭DEBUG。相反,我将以下代码段放在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'}),
    )

在上面的代码片段中,错误页面使用自定义视图,您可以轻松地将其替换为Django的direct_to_template视图。

现在,您可以通过调用其网址来测试500和404页:http://example.com/500http://example.com/404

答案 1 :(得分:27)

在Django 1.6中django.views.generic.simple.direct_to_template不再存在,这些是我对特殊视图的设置:

# urls.py

from django.views.generic import TemplateView
from django.views.defaults import page_not_found, server_error

urlpatterns += [
    url(r'^400/$', TemplateView.as_view(template_name='400.html')),
    url(r'^403/$', TemplateView.as_view(template_name='403.html')),
    url(r'^404/$', page_not_found),
    url(r'^500/$', server_error),
]

答案 2 :(得分:17)

如果您想使用默认的Django 500视图而不是自定义视图:

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^500/$', 'django.views.defaults.server_error'),
        (r'^404/$', 'django.views.generic.simple.direct_to_template', {'template': '404.html'}),
    )

答案 3 :(得分:7)

继续shanyu's answer,在Django 1.3+中使用:

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^500/$', 'django.views.defaults.server_error'),
        (r'^404/$', 'django.views.defaults.page_not_found'),
    )

答案 4 :(得分:5)

两个调试设置都是假的吗?

settings.DEBUG = False
settings.TEMPLATE_DEBUG = False

答案 5 :(得分:1)

urls.py

Transparent

views.py

handler500 = 'project.apps.core.views.handler500'
handler404 = 'project.apps.core.views.handler404'

tests.py

from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponseServerError, HttpResponseNotFound


def handler500(request, template_name='500.html'):
    t = get_template(template_name)
    ctx = Context({})
    return HttpResponseServerError(t.render(ctx))


def handler404(request, template_name='404.html'):
    t = get_template(template_name)
    ctx = Context({})
    return HttpResponseNotFound(t.render(ctx))

答案 6 :(得分:1)

我如何操作并测试自定义错误处理程序

根据View

定义自定义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)

告诉django使用自定义错误处理程序

# 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)

自定义错误处理程序的测试用例

# 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'))

答案 7 :(得分:0)

您可以在主handler404文件中为错误定义handler500views.py,详见答案:

https://stackoverflow.com/a/18009660/1913888

这将返回Django路由到该处理程序时所需的错误。路由到不同的URL名称不需要自定义URL配置。

答案 8 :(得分:0)

在Django版本<3.0中,您应该执行以下操作:

client.py

from unittest import mock

from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings

from .client import Client  # Important, we use our own Client here!


class TestErrors(TestCase):
    """Test errors."""

    @classmethod
    def setUpClass(cls):
        super(TestErrors, cls).setUpClass()
        cls.username = 'admin'
        cls.email = 'admin@localhost'
        cls.password = 'test1234test1234'
        cls.not_found_url = '/i-do-not-exist/'
        cls.internal_server_error_url = reverse('password_reset')

    def setUp(self):
        super(TestErrors, self).setUp()
        User = get_user_model()

        User.objects.create_user(
            self.username,
            self.email,
            self.password,
            is_staff=True,
            is_active=True
        )
        self.client = Client(raise_request_exception=False)

    # Mock in order to trigger Exception and resulting Internal server error
    @mock.patch('django.contrib.auth.views.PasswordResetView.form_class', None)
    @override_settings(DEBUG=False)
    def test_errors(self):
        self.client.login(username=self.username, password=self.password)

        with self.subTest("Not found (404)"):
            response = self.client.get(self.not_found_url, follow=True)
            self.assertNotIn('^admin/', str(response.content))

        with self.subTest("Internal server error (500)"):
            response = self.client.get(self.internal_server_error_url, 
                                       follow=True)
            self.assertNotIn('TypeError', str(response.content))

tests.py

Client

从Django 3.0开始,您可以跳过自定义tests.py的定义,而仅使用@PreAuthorize("hasRole('USER')")中的代码。

答案 9 :(得分:0)

针对Django> 1.6的更新,但未获取

page_not_found() missing 1 required positional argument: 'exception'

this answer的启发:

# urls.py
from django.views.defaults import page_not_found, server_error, permission_denied, bad_request
[...]
if settings.DEBUG:
    # This allows the error pages to be debugged during development, just visit
    # these url in browser to see how these error pages look like.
    urlpatterns += [
    path('400/', bad_request, kwargs={'exception': Exception('Bad Request!')}),
    path('403/', permission_denied, kwargs={'exception': Exception('Permission Denied')}),
    path('404/', page_not_found, kwargs={'exception': Exception('Page not Found')}),
    path('500/', server_error),

答案 10 :(得分:0)

对于 Django > 3.0,只需将 raise_request_exception 值设置为 False

from django.test import TestCase


class ViewTestClass(TestCase):
    def test_error_page(self):
        self.client.raise_request_exception = False
        response = self.client.get(reverse('error-page'))
        self.assertEqual(response.status_code, 500)

文档:https://docs.djangoproject.com/en/3.2/topics/testing/tools/