Django单元测试表单编辑

时间:2010-02-13 15:01:25

标签: django unit-testing django-forms

有人可能已经开发出一种技术来减轻以下惯用单位测试的乏味:

  1. 获取已填充表单数据的网址
  2. 发布修订后的表格,其中包含一个或多个已编辑的字段
  3. 检查回复(利润!)
  4. 第2步是最乏味的,在表单字段中循环。是否有任何省时的黑客来测试Django表格?

    [更新:我没有测试Django表单处理。我正在验证当用户对表单进行更改时,我的应用程序会产生正确的响应。这是一个处理临床信息的应用程序,因此有很多可能的测试反应。]

8 个答案:

答案 0 :(得分:29)

这取决于您要测试的内容。我会比你听起来更精确地测试你的测试。

如果您需要测试的代码是表单验证逻辑,那么我只需在您的测试中直接实例化表单类,传递各种数据字典并调用.is_valid(),检查是否存在正确的错误。无需涉及HTML或HTTP请求。

如果您正在测试它的视图逻辑(IMO应该被最小化),您可能希望使用测试客户端,但您不需要在此级别进行多阶段测试或很多测试。在测试视图逻辑中我不会刮HTML(那是测试模板),我会使用response.context从上下文中提取表单对象。

如果您要测试的是模板包含正确的HTML以使表单实际工作(为了捕获错误,例如忘记在模板中包含formset的管理表单),我使用{{3} }和WebTest,它可以解析您的HTML并轻松填写字段值并像浏览器一样提交表单。

答案 1 :(得分:25)

您可以使用response.contextform.initial来获取发布所需的值:

update_url = reverse('myobject_update',args=(myobject.pk,))

# GET the form
r = self.client.get(update_url)

# retrieve form data as dict
form = r.context['form']
data = form.initial # form is unbound but contains data

# manipulate some data
data['field_to_be_changed'] = 'updated_value'

# POST to the form
r = self.client.post(update_url, data)

# retrieve again
r = self.client.get(update_url)
self.assertContains(r, 'updated_value') # or
self.assertEqual(r.context['form'].initial['field_to_be_changed'], 'updated_value')

答案 2 :(得分:22)

django-webtest非常适合此类测试:

from django_webtest import WebTest

class MyTestCase(WebTest):
    def test_my_view(self)
        form = self.app.get('/my-url/').form
        self.assertEqual(form['my_field_10'].value, 'initial value')
        form['field_25'] = 'foo'
        response = form.submit() # all form fields are submitted

在我看来,这比django测试更好,因为它提供了对django内部的访问,因此支持本机django的response.contextresponse.templatesself.assertTemplateUsedself.assertFormError API 。

另一方面,它比本机django测试客户端更好,因为它具有更强大和简单的API。

我有点偏颇;)但我相信django-webtest现在是编写django测试的最佳方式。

答案 3 :(得分:5)

目前尚不清楚,但有一种猜测是你有这样的测试。

class TestSomething( TestCase ):
    fixtures = [ "..." ]
    def test_field1_should_work( self ):
        response= self.client.get( "url with form data already populated" )
        form_data = func_to_get_field( response )
        form_data['field1']= new value
        response= self.client.post( "url", form_data )
        self.assert()
    def test_field2_should_work( self ):
        response= self.client.get( "url with form data already populated" )
        form_data = func_to_get_field( response )
        form_data['fields']= new value
        response= self.client.post( "url", form_data )
        self.assert()

首先,你做得太多了。简化。

class TestFormDefaults( TestCase ):
    fixtures = [ "some", "known", "database" ]
    def test_get_should_provide_defaults( self ):
        response= self.client.get( "url with form data already populated" )
        self.assert(...)

以上证明默认值填充表单。

class TestPost( TestCase ):
    fixtures = [ "some", "known", "database" ]
    def test_field1_should_work( self ):
        # No need to GET URL, TestFormDefaults proved that it workd.
        form_data= { expected form content based on fixture and previous test }
        form_data['field1']= new value
        response= self.client.post( "url", form_data )
        self.assert()

不要浪费时间为每个“帖子”做“获取”。您可以单独证明GET操作有效。获得该证明后,只需执行POST即可。

如果你的POSTS是高度特定于会话和有状态的,你仍然可以进行GET,但不要理会解析响应。您可以(单独)证明它具有完全正确的字段。

为了优化您的休息,请考虑这一点。

class TestPost( TestCase ):
    fixtures = [ "some", "known", "database" ]
    def test_many_changes_should_work( self ):
        changes = [
            ( 'field1', 'someValue', 'some expected response' ),
            ( 'field2', 'someValue' ),
            ...
        ]
        for field, value, expected in changes:
            self.client.get( "url" ) # doesn't matter what it responds, we've already proven that it works.
            form_data= { expected form content based on fixture and previous test }
            form_data[field]= value
            response self.client.post( "url", form_data )
            self.assertEquas( expected, who knows what )

以上显然会起作用,但它会使测试次数变小。

答案 4 :(得分:1)

仔细考虑为什么需要对此进行单元测试。表单是Django核心功能的一部分,因此Django自己的单元测试非常清楚。如果你所做的只是基本的创建/更新,从你的问题听起来就是这种情况,我认为没有任何理由为此编写单元测试。

答案 5 :(得分:0)

您可能正在寻找可以进行前端测试的工具,例如twillselenium

这两个都生成python代码,可以包含在django测试中,所以当你运行测试时,它会打开网址,发布数据并检查你想要的任何内容!

对于开源可重用的django应用程序,它应该可以帮助您查看为{selenium编写的these tests

答案 6 :(得分:0)

我不知道你为什么需要进行单元测试。听起来像是在测试(和纠正)可能的用户输入,这很简单,只需要Django的表单验证(以及1.2中的模型验证)

答案 7 :(得分:0)

我建议你去看看机器人测试框架或者letucce之类的验收测试级别工具,这些工具被认为只是你想做的事情“我正在验证我的应用程序在用户更改时产生了正确的响应形式“,这听起来更像接受(黑盒)测试而不是单元测试。

对于instace,Robot允许您以表格形式定义测试,您可以定义一次工作流,然后您可以轻松定义一组使用不同数据执行工作流的测试。