如何为django视图编写单元测试? [英] How to write a unit test for a django view?

查看:151
本文介绍了如何为django视图编写单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有问题了解单元测试应该如何设计为django。



从我的理解测试来看,整个视图似乎是不可能的。我们需要区分前提和后期请求的状态。但我不知道如何设计这个。有没有现实生活中的例子?



查看文档中的示例过于简化,仅专注于模型。

  @login_required 
def call_view(request,contact_id):
profile = request.user.get_profile )
如果request.POST:
form = CallsForm(profile.company,request.POST)
如果form.is_valid()
返回HttpResponseRedirect('/ contact /'+ contact_id +'/ calls /')
else:
form = CallsForm(profile.company,instance = call)
variables = RequestContext(request,{'form':form}
返回render_to_response('conversation.html',变量)

更新: / p>

试图成功测试工作,但仍然失败:

  def test_contact_view_success(self):
#同样的,但是有效的数据,那么
self.client.login(username ='username1',password ='password1')
response = self .client.post('/ contact / add /',{u'last_name':[u'John儿子'],})
self.assertRedirects(response,'/')

strong>错误消息:

  AssertionError:响应未按预期重定向:响应代码为200(预计为302 )

我认为这是因为form.is_valid()失败,它不重定向,正确?

解决方案

NB NB! 下面我描述的不是严格的单位测试;为Django视图代码编写独立的单元测试几乎是不可能的。这是更多的一个集成测试...



你是对的,通过你的观点有几个途径:


  1. GET POST 由匿名用户(应重定向到登录页面)

  2. GET POST 个人资料(应该提出一个 UserProfile.DoesNotExist 异常)

  3. GET - 用户(应显示表单)

  4. POST 由具有空白数据的登录用户(应显示表单错误) li>
  5. POST 由具有无效数据的登录用户(应显示表单错误)

  6. POST 由具有有效数据(应重定向)的登录用户

测试1。真的只是测试 @login_required ,所以你可以跳过它。我倾向于测试它(只是为了防止我或别人忘记使用该装饰器)。



我不知道失败的情况(一个500错误页面)在2.是你真正想要的我会解决你想要发生的事情(也许使用 get_or_create() ,或者捕获 DoesNotExist 异常并创建一个新的配置文件) / p>

根据您有多少自定义验证,4.可能不需要进行测试。



在任何在上述情况下,我将会执行以下操作:

 从django.test导入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 )#在fixture中定义或在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',{})#空白数据字典
self.assertFormError(response,'form','some_field','这个字段是必需的。$)
#等...

def test_call_view_fails_invalid(self):
#如上,但在字典中为空b
$ b def test_call_view_fails_invalid(self):
#同样的,但是有效的数据,那么
self.assertRedirects(response,'/ contact / 1 / calls /')

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



希望这有帮助。


I have problems understanding how the unit tests should be designed for django.

From my understanding testing the whole view in one go seems impossible. We need to distinguish between pre-post and post states of request. But I have no idea how to design this. Is there any real life example?

Looking at the documentation the examples are too simplified and only focused on the model.

@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)

update:

trying to make a success test work, but it still fails:

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, '/')

error message:

AssertionError: Response didn't redirect as expected: Response code was 200 (expected 302)

I think this is because the form.is_valid() fails and it doesn't redirect, correct?

解决方案

NB NB! What I describe below isn't strictly a "unit test"; it's almost impossible to write an independent unit test for Django view code. This is more of an integration test...

You're right that there are several pathways through your view:

  1. GET or POST by anonymous user (should redirect to login page)
  2. GET or POST by logged-in user with no profile (should raise a UserProfile.DoesNotExist exception)
  3. GET by logged-in user (should show the form)
  4. POST by logged-in user with blank data (should show form errors)
  5. POST by logged-in user with invalid data (should show form errors)
  6. POST by logged-in user with valid data (should redirect)

Testing 1. is really just testing @login_required, so you could skip it. I tend to test it anyway (just in case I or someone else have forgotten to use that decorator).

I'm not sure the failure case (a 500 error page) in 2. is what you really want. I would work out what you want to happen instead (perhaps use get_or_create(), or catch the DoesNotExist exception and create a new profile that way).

Depending on how much custom validation you have, 4. may not really need to be tested.

In any case, given all of the above, I would do something like:

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/')

Obviously, a drawback here is hard-coded URLs. You could either use reverse() in your tests or build requests using RequestFactory and call your views as methods (rather than by URL). With the latter method, though, you still need to use hard-coded values or reverse() to test redirect targets.

Hope this helps.

这篇关于如何为django视图编写单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆