【问题标题】:How do I test Django views when they don't return values当 Django 视图不返回值时如何测试它们
【发布时间】:2023-04-08 20:36:01
【问题描述】:

我是 Django 新手。我已经完成了一些教程,编写了一些模型、视图、表单等,但我不明白如何测试它们,因为要么什么都没有返回,要么返回的任何东西都被严格限制在术语上没有意义测试。

例如这里有两个视图类:

class ListBlogPostView(ListView):
    model = BlogPost
    template_name = 'app/blogpost_list.html'


class CreateBlogPostView(CreateView):
    model = BlogPost
    template_name = 'app/blogpost_edit.html'
    form_class = BlogPostForm

    def get_success_url(self):
        return reverse('blogpost-list')

    def get_context_data(self, **kwargs):
        context = super(CreateBlogPostView, self).get_context_data(**kwargs)
        context['action'] = reverse('blogpost-new')
        return context

第一个 ListBlogPostView 不返回任何内容。我怎样才能检查它是否正常工作?

第二个有几个函数,但它们的返回值不是我可以用断言测试的东西

我怎么能对 Django 使用 TDD 方法?

我习惯在 Visual Studio 中使用 nunit 和 MS“单元”测试、模拟等

【问题讨论】:

    标签: django unit-testing django-testing


    【解决方案1】:

    实际上,Django 的 generic 基于类的视图并不是无缘无故称为泛型的。

    您可以查看ListViewCreateView的来源。


    ListView 有一个 GET 方法处理程序:

    class BaseListView(MultipleObjectMixin, View):
        """A base view for displaying a list of objects."""
        def get(self, request, *args, **kwargs):
            self.object_list = self.get_queryset()
            allow_empty = self.get_allow_empty()
    
            if not allow_empty:
               # ...
    
            context = self.get_context_data()
            return self.render_to_response(context)
    

    它返回一个有效的 Django 响应并且可以在 tests.py 中测试。


    如果您查看CreateView,它继承自BaseCreateView(就像ListView 继承自BaseListView):

    class BaseCreateView(ModelFormMixin, ProcessFormView):
        """
        Base view for creating an new object instance.
        Using this base class requires subclassing to provide a response mixin.
        """
        def get(self, request, *args, **kwargs):
            # ...
    
        def post(self, request, *args, **kwargs):
            # ...
    

    也继承自ProcessFormView

    class ProcessFormView(View):
        """Render a form on GET and processes it on POST."""
        def get(self, request, *args, **kwargs):
            """Handle GET requests: instantiate a blank version of the form."""
            return self.render_to_response(self.get_context_data())
    
        def post(self, request, *args, **kwargs):
            """
            Handle POST requests: instantiate a form instance with the passed
            POST variables and then check if it's valid.
            """
            form = self.get_form()
            if form.is_valid():
                return self.form_valid(form)
            else:
                return self.form_invalid(form)
    

    GET 请求将产生一个有效的响应。如您所见,这里的 POST 方法处理程序根据表单状态返回 self.form_valid(form)self.form_invalid(form)

    这两个方法的来源可以在ViewMixin看到:

    def form_valid(self, form):
        """If the form is valid, redirect to the supplied URL."""
        return HttpResponseRedirect(self.get_success_url())
    
    def form_invalid(self, form):
        """If the form is invalid, render the invalid form."""
        return self.render_to_response(self.get_context_data(form=form))
    

    这两种方法都返回一个有效的可测试 Django 响应。


    总之,你的ListBlogPostViewCreateBlogPostView都可以直接在tests.py中测试。您只需要更详细地查看the implementation of Django's generic views开源的力量!

    【讨论】:

    • 这太棒了!我不知道我可以深入了解并获得内置 Django 方法的来源。它使一切变得更加清晰,非常感谢。
    【解决方案2】:

    测试view 不像函数大多数时候不会有返回值。我这样做的方法是断言html 响应。

    所以对于ListBlogPostView,它取决于blogpost_list.html 模板中的内容。

    一般视图测试应如下所示:

    class ListBlogPostViewTest(TestCase):
    
        def test_blogpost_list_view(self): 
            response = self.client.get(reverse('blogpost-list'))
            html = response.content.decode('utf8')  
            self.assertTrue(html.startswith('<html>'))
            self.assertIn('<title>BlogPost lists</title>', html)  
            self.assertTrue(html.endswith('</html>'))
    

    对于具有contextview,您实际上可以检查它是否被正确检索并传递给查看。

    blogPost = BlogPost.object.get(id=1)
    self.assertEqual(response.context['blogPost'].name, blogPost.name)
    

    我怎么能对 Django 使用 TDD 方法?

    对于 TDD,您只需在创建 html 视图之前先对其进行测试。这实际上取决于您喜欢测试的细节并找到平衡点。我更喜欢主要在设置的context 上进行测试,重要的html 元素在view 中。

    【讨论】:

    • 非常感谢。没有什么比如何组合解决方案的实际示例更好的了
    【解决方案3】:

    你仍然可以测试很多参数 -

    • 获取和发布请求的状态代码
    • 上下文数据中的变量(例如表单)
    • 使用了断言模板
    • 在创建视图的情况下根据发布请求创建对象
    • 使用状态码检查权限

    问题是对 django 视图的测试在技术上是集成测试。只要您的测试足够细化,也就是说您不在视图中测试表单或模型的代码,只要您遵循经典 TDD,我看不出有任何问题。

    【讨论】:

    • 我没有想到要断言模板、检查权限等,这是个好主意
    猜你喜欢
    • 1970-01-01
    • 2022-01-07
    • 2011-02-21
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多