有人可能已经开发出一种技术来减轻以下惯用单位测试的乏味:
第2步是最乏味的,在表单字段中循环。是否有任何省时的黑客来测试Django表格?
[更新:我没有测试Django表单处理。我正在验证当用户对表单进行更改时,我的应用程序会产生正确的响应。这是一个处理临床信息的应用程序,因此有很多可能的测试反应。]
答案 0 :(得分:29)
这取决于您要测试的内容。我会比你听起来更精确地测试你的测试。
如果您需要测试的代码是表单验证逻辑,那么我只需在您的测试中直接实例化表单类,传递各种数据字典并调用.is_valid(),检查是否存在正确的错误。无需涉及HTML或HTTP请求。
如果您正在测试它的视图逻辑(IMO应该被最小化),您可能希望使用测试客户端,但您不需要在此级别进行多阶段测试或很多测试。在测试视图逻辑中我不会刮HTML(那是测试模板),我会使用response.context从上下文中提取表单对象。
如果您要测试的是模板包含正确的HTML以使表单实际工作(为了捕获错误,例如忘记在模板中包含formset的管理表单),我使用{{3} }和WebTest,它可以解析您的HTML并轻松填写字段值并像浏览器一样提交表单。
答案 1 :(得分:25)
您可以使用response.context
和form.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.context
,response.templates
,self.assertTemplateUsed
和self.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)
您可能正在寻找可以进行前端测试的工具,例如twill或selenium
这两个都生成python代码,可以包含在django测试中,所以当你运行测试时,它会打开网址,发布数据并检查你想要的任何内容!
对于开源可重用的django应用程序,它应该可以帮助您查看为{selenium编写的these tests。
答案 6 :(得分:0)
我不知道你为什么需要进行单元测试。听起来像是在测试(和纠正)可能的用户输入,这很简单,只需要Django的表单验证(以及1.2中的模型验证)
答案 7 :(得分:0)
我建议你去看看机器人测试框架或者letucce之类的验收测试级别工具,这些工具被认为只是你想做的事情“我正在验证我的应用程序在用户更改时产生了正确的响应形式“,这听起来更像接受(黑盒)测试而不是单元测试。
对于instace,Robot允许您以表格形式定义测试,您可以定义一次工作流,然后您可以轻松定义一组使用不同数据执行工作流的测试。