如何将TDD应用于Django基于类的通用视图?

24 投票
3 回答
6439 浏览
提问于 2025-04-17 08:50

在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_viewdispatch 这些方法。它们对于理解框架如何与视图对象互动非常重要。

最重要的一点是,视图方法是在请求-响应过程中被调用的,因此它们可以依赖于 self.requestself.argsself.kwargs 在被调用之前就已经存在,所以一定要确保这一点。

撰写回答