Тестирование ожидаемого 404 с помощью тестового клиента Django приводит к необработанному исключению

Я использую тестовый клиент Django, django.test.client.Client, для тестирования некоторых представлений в приложении Django. В частности, я тестирую случай, когда представление вызывает метод get_object_or_404, а объекта там нет, поэтому должно быть возвращено 404.

Мой тестовый код выглядит так:

class ViewTests(TestCase):
    fixtures=['test.json']

    def test_thing_not_there_get(self):
        url = '/foo/30afda98-b9d7-4e26-a59a-76ac1b6a001f/'
        c = django.test.client.Client()
        response = c.get(url)
        self.assertEqual(response.status_code, 404)

Однако вместо этого я получаю необработанную ошибку исключения в коде представления:

python projects/unittests/manage.py test 
Creating test database for alias 'default'...
......ERROR:root:Unhandled Exception on request for http://testserver/foo/30afda98-b9d7-4e26-a59a-76ac1b6a001f/
Traceback (most recent call last):
  File "/Users/lorin/.virtualenvs/myvenv/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Users/lorin/.virtualenvs/myvenv/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 39, in wrapped_view
    resp = view_func(*args, **kwargs)
  File "/Users/lorin/.virtualenvs/myvenv/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 52, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/lorin/django-myvenv/apps/myvenv_desktop/views.py", line 85, in foo_view
    instance = get_object_or_404(Foo, uuid=foo_uuid)
  File "/Users/lorin/.virtualenvs/myvenv/lib/python2.7/site-packages/django/shortcuts/__init__.py", line 115, in get_object_or_404
    raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
Http404: No Foo matches the given query.

Согласно документации Django 1.3

Единственными исключениями, невидимыми для тестового клиента, являются Http404, PermissionDenied и SystemExit. Django перехватывает эти исключения и преобразует их в соответствующие коды ответов HTTP. В этих случаях вы можете проверить response.status_code в своем тесте.

Почему в этом случае Django не перехватывает исключение Http404?

Обратите внимание, что (в соответствии с документацией) исключение не передается в тестовый клиент. Если я попытаюсь поймать исключение на стороне клиента:

with self.assertRaises(django.http.Http404):
    response = c.get(url)

Я получаю ту же ошибку, а также дополнительную ошибку:

AssertionError: Http404 not raised

person Lorin Hochstein    schedule 22.01.2012    source источник
comment
Но, согласно вашему ответу, django должен возвращать код ответа 404, это ошибка django, не так ли?   -  person AlejandroPerezLillo    schedule 15.01.2013


Ответы (2)


Я знаю, что это было давно, но я решил это, поэтому решил, что им стоит поделиться. Что вам нужно сделать, так это настроить обработчик ошибок в вашем коде. Например, у меня есть:

в urls.py:

from myapp.views import error_handler
handler404 = error_handler.error404

и функция error404:

from django.http import HttpResponseNotFound
def error404(request):
    t = loader.get_template('404.html')
    html = t.render(Context())

    return HttpResponseNotFound(html)

Если вы отправите объект HttpResponseNotFound, он будет интерпретирован как код состояния 404.

ИЗМЕНИТЬ

В более новых версиях django можно просто поместить 404.html в каталог шаблонов. Вышеупомянутый контроллер необходим только в том случае, если вам нужно больше логики, чем просто отображение страницы с ошибкой.

person KVISH    schedule 21.02.2013

При дальнейшем рассмотрении кажется, что тест проходит так, как написано: сообщение об ошибке на самом деле не соответствует сбою теста.

person Lorin Hochstein    schedule 22.01.2012