如何将TDD应用于Django基于类的通用视图?
在Django中,基于类的通用视图涉及到框架的一些工作,这让我觉得在测试驱动开发(TDD)风格下很难使用它们。现在我使用TestClient从模拟的HTTP堆栈中访问视图,但我更希望能在进行“功能性”测试之前,先对特定的方法(比如重写的get_object和get_queryset)进行单元测试。
有没有什么快速的方法可以获得一个合适的ClassView实例,以便对它进行单元测试呢?
3 个回答
5
我今天在找一个简单的解决方案来处理同样的问题,发现了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)
8
我不确定这是不是你想要的,但这是我尝试对我的视图进行单元测试的一个例子(下面的代码还没有测试):
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)
我还建议你看看Filip在他的回答中提到的文档。
17
一般来说,这包括通过 RequestFactory
创建一个请求,并用关键字参数来实例化视图类。之后,你可以调用任何视图方法并评估结果,同时传入所需的参数。
我建议你查看一下基础的 View
类,特别是 __init__
、as_view
和 dispatch
这些方法。它们对于理解框架如何与视图对象互动非常重要。
最重要的一点是,视图方法是在请求-响应过程中被调用的,因此它们可以依赖于 self.request
、self.args
和 self.kwargs
在被调用之前就已经存在,所以一定要确保这一点。