django框架从零开始_011_测试view
来源:互联网 发布:arr数组怎么转化成json 编辑:程序博客网 时间:2024/06/03 16:50
参考:https://docs.djangoproject.com/en/1.9/intro/tutorial05/
上一个测试我们了解到了如何测试一个方法是否如我们预期的工作方式一致,接下来我们来看看其他功能。django提供了一个测试客户端,可以在view层面模拟用户的操作。我们可以在tests.py或者shell中使用它。
让我们从shell开始。在shell测试中我们需要一些在tests.py中不必使用的操作。首先,我们要来设置运行环境:
>>> from django.test.utils import setup_test_environment>>> setup_test_environment()
setup_test_environment() 方法会安装一些模版渲染器,使得我们可以检查responses的一些额外属性,比如respone.context之类。需要注意的是,这个方法并不会安装test数据库,所以以下操作也许会因为个人之前question的不同而导致输出不同。
设置完环境后,我们需要来导入Client类:
>>> from django.test import Client>>> # create an instance of the client for our use>>> client = Client()
接下来,我们就可以让client来做一些我们想要做的事情
>>> # get a response from '/'>>> response = client.get('/')>>> # we should expect a 404 from that address>>> response.status_code404>>> # on the other hand we should expect to find something at '/polls/'>>> # we'll use 'reverse()' rather than a hardcoded URL>>> from django.core.urlresolvers import reverse>>> response = client.get(reverse('polls:index'))>>> response.status_code200>>> response.contentb'\n\n\n <p>No polls are available.</p>\n\n'>>> # note - you might get unexpected results if your ``TIME_ZONE``>>> # in ``settings.py`` is not correct. If you need to change it,>>> # you will also need to restart your shell session>>> from polls.models import Question>>> from django.utils import timezone>>> # create a Question and save it>>> q = Question(question_text="Who is your favorite Beatle?", pub_date=timezone.now())>>> q.save()>>> # check the response once again>>> response = client.get('/polls/')>>> response.contentb'\n\n\n <ul>\n \n <li><a href="/polls/1/">Who is your favorite Beatle?</a></li>\n \n </ul>\n\n'>>> # If the following doesn't work, you probably omitted the call to>>> # setup_test_environment() described above>>> response.context['latest_question_list'][<Question: Who is your favorite Beatle?>]
现在我们的polls/index显示的question包括了那些还未发布的(pub_date在future的),让我们来改进它。
在之前的代码中,我们基于generic.ListView对index定义如下:
class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): """Return the last five published questions.""" return Question.objects.order_by('-pub_date')[:5]
显然,我们需要更新get_queryset()方法,检查question的pubdate。如下:
def get_queryset(self): ''' return the last five published questions.''' return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
.filter(pub_date__lte=timezone.now())是一个过滤器,返回pub_date小于等于timezone.now()的list。
下面让我们来测试它。如果不使用测试用例系统,你需要手动建立Question,运行服务器,检查结果是否如你所愿。这显然太麻烦了。以下我们使用tests.py来进行测试,和用shell方法类似。
首先我们设置一个快速建立Question的方法,以便在后续代码中调用:
def create_question(question_text, days): time = timezone.now() + datetime.timedelta(days=days) return Question.objects.create(question_text=question_text, pub_date=time)
接下来编写测试用例。记得导入reverse()先:
class QuestionViewTests(TestCase): def test_index_view_with_no_question(self): """ If no questions exist, an appropriate message should be displayed. """ response = self.client.get(reverse('polls:index')) self.assertEqual(response.status_code, 200) #print(response.context) self.assertContains(response, 'No polls are available.') self.assertQuerysetEqual(response.context['latest_question_list'], []) def test_index_view_with_a_past_question(self): """ Questions with a pub_date in the past should be displayed on the index page. """ create_question(question_text="Past question.", days=-30) response = self.client.get(reverse('polls:index')) self.assertQuerysetEqual( response.context['latest_question_list'], ['<Question: Past question.>'] ) def test_index_view_with_a_future_question(self): """ Questions with a pub_date in the future should not be displayed on the index page. """ create_question(question_text="Future question.", days=30) response = self.client.get(reverse('polls:index')) self.assertContains(response, "No polls are available.", status_code=200) self.assertQuerysetEqual(response.context['latest_question_list'], []) def test_index_view_with_future_question_and_past_question(self): """ Even if both past and future questions exist, only past questions should be displayed. """ create_question(question_text="Past question.", days=-30) create_question(question_text="Future question.", days=30) response = self.client.get(reverse('polls:index')) self.assertQuerysetEqual( response.context['latest_question_list'], ['<Question: Past question.>'] ) def test_index_view_with_two_past_questions(self): """ The questions index page may display multiple questions. """ create_question(question_text="Past question 1.", days=-30) create_question(question_text="Past question 2.", days=-5) response = self.client.get(reverse('polls:index')) self.assertQuerysetEqual( response.context['latest_question_list'], ['<Question: Past question 2.>', '<Question: Past question 1.>'] )
其中:
- test_index_view_with_no_question测试了空question时候的返回对象的['latest_question_list']值和status_code。
- test_index_view_with_a_past_question测试了单个正常Question时候的显示。
- test_index_view_with_a_future_question测试了pub_date在未来时候的question显示。每一个方法运行时,数据库都会重置,所以之前方法保存的question不会在其中出现。
关于asserQuerysetEqual(),请参考:https://docs.djangoproject.com/en/1.9/topics/testing/tools/#django.test.TransactionTestCase.assertQuerysetEqual
class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html' def get_queryset(self): """ Excludes any questions that aren't published yet. """ return Question.objects.filter(pub_date__lte=timezone.now())
OK,我们在tests.py中继续添加一些例子,来保证DetailView的运行:
class QuestionDetailTests(TestCase): def test_detail_view_with_a_future_question(self): """ The detail view of a question with a pub_date in the future should return a 404 not found. """ future_question = create_question(question_text='Future question', days=5) response = self.client.get(reverse('polls:detail', args=(future_question.id,))) self.assertEqual(response.status_code, 404) def test_detail_view_with_a_past_question(self): """ The detail view of a question with a pub_date in the past should display the question's text. """ past_question = create_question(question_text='Past Question.', days=-5) response = self.client.get(reverse('polls:detail', args=(past_question.id,))) #print(response.context) self.assertContains(response, past_question.question_text, status_code=200)
类似的,我们也可以继续添加对于ResultsView的测试。例如:我们可以让没有choice的Question不被展示;或者可以让没有choice的Question只被管理员用户可见,不被其他用户可见,等等。总之,不论任何你想要的功能,你都应该为其增添测试,不管你是先有测试用例再完成功能,还是先有功能再添加测试用例。
经过这些测试,你也许会发现,这些测试用例代码越来越大,甚至超过你的apps的代码,但是没关系,我们有一个原则:
测试用例越多越好(When testing, more is better)
虽然这些测试代码量可能会疯长,但是没关系,let them grow。对于大多数情况,你只需要编写一次测试用例,然后就可以把他们忘记了;有些时候你需要更新这些测试用例,但是挂了的测试用例仍然可以指导我们哪里需要修改,直至被修复;有些时候,随着开发工作的进展,有的测试用例是冗余的,但是没关系,冗余测试仍然是好的事情。
只要你的测试用例被很好的管理,他们不会失去控制。你应该遵守如下比较有用的规则:
- 对于每个model或者view,编写独立的测试类
- 对于每一种测试情况,编写不同的测试方法
- 测试方法名字应该对测试内容有说明含义
- django框架从零开始_011_测试view
- django框架从零开始_010_自动化测试
- django框架从零开始_002_helloworld
- django框架从零开始_001_安装
- django框架从零开始_003_数据库
- django框架从零开始_006_draft views
- django框架从零开始_004_数据库_API
- django框架从零开始_005_管理界面
- django框架从零开始_007_view以及模版页
- django框架从零开始_009_通用页面
- Django- 从零开始
- Django 从零开始
- 测试小卒子--python--Django 测试框架
- django框架从零开始_008_页面元素 表单处理
- Django View
- Django-View
- Django View
- 测试从零开始
- <<c>>二叉查找树
- CSS的分类、选择器、文档结构
- TreeSet的排序两种实现方式Comparator和Comparable
- hdu_5690_All X(找循环节)
- Eclipse+NDK 环境配置
- django框架从零开始_011_测试view
- iOS学习笔记之七--图片的移动
- 精度问题
- (创建型模式)FACTORY——简单工厂模式
- Object Following for UAV(无人机物体跟随)
- 利用VisuAlgo通过动画学习算法和数据结构
- 欢迎使用CSDN-markdown编辑器
- 参数估计:贝叶斯思想和贝叶斯参数估计
- 单一职责原则(SRP)