我在理解如何为django设计单元测试时遇到了问题。
根据我的理解,一次性测试整个视图似乎是不可能的。我们需要区分请求的前后状态。但我不知道如何设计这个。有没有现实生活中的例子?
查看文档时,示例过于简化,仅关注模型。
@login_required
def call_view(request, contact_id):
profile = request.user.get_profile()
if request.POST:
form = CallsForm(profile.company, request.POST)
if form.is_valid()
return HttpResponseRedirect('/contact/' + contact_id + '/calls/')
else:
form = CallsForm(profile.company, instance=call)
variables = RequestContext(request, {'form':form}
return render_to_response('conversation.html', variables)
更新
尝试成功完成测试工作,但仍然失败:
def test_contact_view_success(self):
# same again, but with valid data, then
self.client.login(username='username1', password='password1')
response = self.client.post('/contact/add/', {u'last_name': [u'Johnson'], })
self.assertRedirects(response, '/')
错误消息:
AssertionError: Response didn't redirect as expected: Response code was 200 (expected 302)
我认为这是因为form.is_valid()失败并且没有重定向,对吗?
答案 0 :(得分:98)
NB NB! 我在下面描述的并不是严格意义上的“单元测试”;为Django视图代码编写独立的单元测试几乎是不可能的。这更像是一次集成测试...
你认为你的观点有几条路径是正确的:
GET
或POST
(应重定向到登录页面)GET
或POST
没有个人资料(应提出UserProfile.DoesNotExist
例外)GET
(应显示表单)POST
,空白数据(应显示表单错误)POST
(应显示表单错误)POST
(应重定向)测试 1 实际上只是测试@login_required
,因此您可以跳过它。无论如何我倾向于测试它(以防我或其他人忘记使用该装饰器)。
我不确定 2 中的失败案例(500错误页面)是您真正想要的。我会想出你想要发生的事情(也许是use get_or_create()
,或者抓住DoesNotExist
例外并以这种方式创建一个新的配置文件。)
根据您的自定义验证量, 4 可能不需要进行测试。
无论如何,鉴于上述所有情况,我会做类似的事情:
from django.test import TestCase
class TestCalls(TestCase):
def test_call_view_denies_anonymous(self):
response = self.client.get('/url/to/view', follow=True)
self.assertRedirects(response, '/login/')
response = self.client.post('/url/to/view', follow=True)
self.assertRedirects(response, '/login/')
def test_call_view_loads(self):
self.client.login(username='user', password='test') # defined in fixture or with factory in setUp()
response = self.client.get('/url/to/view')
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'conversation.html')
def test_call_view_fails_blank(self):
self.client.login(username='user', password='test')
response = self.client.post('/url/to/view', {}) # blank data dictionary
self.assertFormError(response, 'form', 'some_field', 'This field is required.')
# etc. ...
def test_call_view_fails_invalid(self):
# as above, but with invalid rather than blank data in dictionary
def test_call_view_fails_invalid(self):
# same again, but with valid data, then
self.assertRedirects(response, '/contact/1/calls/')
显然,这里的缺点是硬编码的URL。您可以在测试中use reverse()
或build requests using RequestFactory
并将您的观点称为方法(而不是通过网址)。但是,使用后一种方法,您仍然需要使用硬编码值或reverse()
来测试重定向目标。
希望这有帮助。
答案 1 :(得分:5)
Django附带了一个测试客户端,可用于测试完整的请求/响应周期:The docs包含一个向给定URL发出get请求并声明状态代码以及模板上下文的示例。您还需要一个测试,它执行POST并按预期断言成功重定向。