Django单元测试表单编辑

Jef*_*uer 25 django unit-testing django-forms

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

  1. 获取已填充表单数据的URL
  2. 发布修改后的表单,其中包含一个或多个字段
  3. 检查回复(利润!)

第2步是最乏味的,在表单字段中循环.是否有任何节省时间的黑客用于测试Django表单?

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

Car*_*yer 30

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

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

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

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


chr*_*isv 26

您可以使用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')
Run Code Online (Sandbox Code Playgroud)


Mik*_*bov 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
Run Code Online (Sandbox Code Playgroud)

在我看来,它比斜纹Django的测试更好,因为它提供了访问Django的内部因此本地Django的response.context,response.templates,self.assertTemplateUsedself.assertFormError被支持的API.

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

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


S.L*_*ott 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()
Run Code Online (Sandbox Code Playgroud)

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

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(...)
Run Code Online (Sandbox Code Playgroud)

以上证明了默认值填充表单.

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()
Run Code Online (Sandbox Code Playgroud)

不要浪费时间为每个"帖子"做"获取".您可以单独证明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 )
Run Code Online (Sandbox Code Playgroud)

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