Как TDD может быть применен к Generic Views на основе Django?
Поскольку класс Generic Views в Django включает некоторую работу в рамках структуры, мне очень сложно работать с ними в стиле TDD. Теперь я использую TestClient для доступа к представлению из http mocked stack, но я бы предпочел правильно убрать определенные методы (переопределения get_object и get_queryset) перед "функциональным" тестированием с помощью TestClient.
Есть ли (быстрый) способ получить правильный экземпляр ClassView для выполнения unit test на нем?
Ответы
Ответ 1
Как правило, это будет включать создание запроса через RequestFactory
и создание экземпляра класса представления с аргументами ключевого слова. Впоследствии вы можете вызвать любой из методов представления и оценить результат, передав все необходимые аргументы.
Я бы рекомендовал вам просмотреть базовый класс View
, в частности __init__
., as_view
и dispatch
. Они имеют решающее значение для понимания того, как среда взаимодействует с объектами представления.
Самый важный бит, чтобы заметить, что методы просмотра ожидаются, будут вызваны во время процесса запроса-ответа, поэтому им можно будет полагаться на self.request
, self.args
и self.kwargs
, чтобы присутствовать, re, поэтому убедитесь, что у вас это покрыто.
Ответ 2
Не уверен, что это именно то, что вы ищете, но это пример того, как я пытаюсь unit test мои представления (непроверенный код ниже):
import unittest
from django.core.urlresolvers import reverse
from django.test.client import RequestFactory
from ..views import MyClassBasedView
class MyClassBasedViewTestCase(unittest.TestCase):
def setUp(self):
self.factory = RequestFactory()
def test_list_view(self):
request = self.factory.get(reverse('your_url'))
# additional params can go after request
response = MyClassBasedView.as_view()(request)
self.assertEqual(response.status_code, 200)
Я также рекомендую посмотреть документацию, о которой Филип сказал в его ответ.
Ответ 3
Я искал простое решение для той же проблемы сегодня и нашел этот действительно отличный блог-пост от Benoît Bryon (спасибо!).
Он предложил следующую функцию:
def setup_view(view, request, *args, **kwargs):
"""Mimic as_view() returned callable, but returns view instance.
args and kwargs are the same you would pass to ``reverse()``
"""
view.request = request
view.args = args
view.kwargs = kwargs
return view
Пример
Я хотел протестировать следующий CBV:
class CreateList(CreateView):
model = Item
form_class = NewListForm
template_name = 'lists/home_page.html'
def form_valid(self, form):
list_ = form.save(owner=self.request.user)
return redirect(list_)
Необходимые тесты для аргументов метода form.save
и для аргументов redirect
, которые должны быть возвратным значением первого. Эти тесты будут выглядеть примерно так:
class CreateListTest(unittest.TestCase):
def setUp(self):
self.request = HttpRequest()
self.request.user = Mock()
self.form = Mock()
self.view = setup_view(views.CreateList(), self.request)
def test_form_dot_save_called_with_user(self):
self.view.form_valid(self.form)
self.form.save.assert_called_once_with(owner=self.request.user)
@patch('lists.views.redirect')
def test_redirect(self, mock_redirect):
self.view.form_valid(self.form)
mock_redirect.assert_called_once_with(self.form.save.return_value)