如何为 django 视图编写单元测试?

我在理解应该如何为 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()失败了,而且它没有重定向,对吗?

50088 次浏览

Django 附带了一个测试客户机,可以用来测试完整的请求/响应周期: 医生包含一个例子,向给定的 URL 发出 get 请求,并断言状态代码和模板上下文。您还需要一个测试,该测试执行 POST 并按照预期断言成功的重定向。

NB NB!这不是严格意义上的“单元测试”; 为 Django 视图代码编写独立的单元测试很困难,也不常见。这更像是一个综合测试。

你是对的,你的观点有几种途径:

  1. GETPOST由匿名用户(应重定向到登录页面)
  2. 没有配置文件的登录用户的 GETPOST(应该引发 UserProfile.DoesNotExist异常)
  3. 通过登录用户的 GET(应该显示表单)
  4. POST由登录用户提供空白数据(应显示表单错误)
  5. POST由登录用户带有无效数据(应显示表单错误)
  6. POST由具有有效数据的登录用户(应重定向)

测试 1实际上只是测试 @login_required,所以您可以跳过它。无论如何,我倾向于测试它(以防我们忘记使用那个装饰器)。

我不确定 2中的失败案例(500个错误页面)是您真正想要的。我会计算出您希望发生什么(可能是 使用 get_or_create(),或者捕获 DoesNotExist异常并以这种方式创建一个新的配置文件) ,或者重定向到一个页面,以便用户创建一个配置文件。

取决于您有多少自定义验证,4可能并不真正需要进行测试。

无论如何,考虑到以上所有因素,我都会这样做:

from django.test import TestCase


class TestCalls(TestCase):
def test_call_view_deny_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_load(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_fail_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_fail_invalid(self):
# as above, but with invalid rather than blank data in dictionary


def test_call_view_success_invalid(self):
# same again, but with valid data, then
self.assertRedirects(response, '/contact/1/calls/')

显然,这里的一个缺点是硬编码的 URL。您可以在测试中使用 使用 reverse()使用 RequestFactory构建请求,并将视图作为方法(而不是通过 URL)调用。但是,对于后一种方法,您仍然需要使用硬编码的值或 reverse()来测试重定向目标。

希望这个能帮上忙。