简单的待办事项清单网站--实现基本功能
来源:互联网 发布:淘宝魔兽带团本 编辑:程序博客网 时间:2024/06/05 20:19
这下要动真格的了。我们的流程是:编写功能测试–编写单元测试–完成各个单元(单元测试通过)–完成功能(功能测试通过)–重构与优化。这次分为两步–建立成功基本网站–实现基本功能——能够保存并显示你的代办事项。
那什么是功能测试和单元测试呢?简单来说就是:
功能测试:以用户的视角测试网站。
单元测试:以程序员的视角测试网站。
所以我们的功能实现是以功能测试为基准的,而单元测试则渗透进码代码的过程中。
一、编写一个最简单的可用网站
可用的网站有哪些要求呢?
打开一个网址,然后你看到了一个静态的网页。这就是最简单可用网站。这是个很好的例子:http://motherfuckingwebsite.com/
emm…显然我们不能做这样一个网站,相反,我们要做的正好是其反对的。不管怎样,第一目标就类似于这个网站。
那么你打开上一个完成的项目了吗?就这个:
打开控制台,输入py -3 manage.py runserver或python manage.py runserver把网站运行起来。
先进行功能测试。对了,上次编写的使用selenium的python文件就是功能测试文件。
我们的第一步就是实现上次的测试内容。简单来说就是让localhost:8000变成一个title含有‘To-Do’网页。
回到上次的测试结果:
Traceback (most recent call last): File
“C:\Users\giligiliai\Desktop\Hello-World\1.py”, line 17, in
test_new_user_get_the_title
self.assertIn(‘To-Do’,self.browser.title) AssertionError: ‘To-Do’ not found in ‘Welcome to Django’
———————————————————————- Ran 1 test in 10.370s
FAILED (failures=1)
那么现在正式开始。在控制台中ctrl+c关闭网站,输入:py -3 manage.py startapp list或python manage.py startapp list建立第一个应用然后你会发现这样的文件夹:
接下来要加速了:
打开hhhh文件夹中的settings.py,补充INSTALLED_APPS为:
settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'list',]
打开list中的test.py,编写单元测试:
test.py
from django.test import TestCasefrom django.core.urlresolvers import resolvefrom django.http import HttpRequestfrom list.views import homepageclass HomepageTest(TestCase): def test_root_url_resolve_view(self): temp=resolve('/') self.assertEqual(temp.func,homepage) def test_homepage_return_correct_html(self): request=HttpRequest() response=homepage(request) self.assertTrue(response.content.startswith(b'<html>')) self.assertIn(b'<title>To-Do lists</title>',response.content) self.assertTrue(response.content.endswith(b'</html>'))
运行py -3 manage.py test 运行django自带test方法。得到:
ImportError: Failed to import test module: list.tests Traceback (most
recent call last): File
“C:\Users\giligiliai\AppData\Local\Programs\Python\Python36-32\lib\unittest\loader.py”,
line 428, in _find_test_path
module = self._get_module_from_name(name) File “C:\Users\giligiliai\AppData\Local\Programs\Python\Python36-32\lib\unittest\loader.py”,
line 369, in _get_module_from_name
import(name) File “G:\hhhh\list\tests.py”, line 5, in
from list.views import homepage ImportError: cannot import name ‘homepage’———————————————————————- Ran 1 test in 0.001s
FAILED (errors=1) Destroying test database for alias ‘default’…
这里再说明一下,单元测试的目的是防止我们(程序员)犯下愚蠢的错误,完整的测试驱动方法应该以功能测试的成功为目标,以单元测试为代码编写的驱动。
进入list–views.py编写:
views.py
from django.shortcuts import renderdef homepage(request): return render(request,'homepage.html')
进入hhhh–url.py编写
url.py
from django.conf.urls import urlfrom django.contrib import adminfrom list import viewsurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$',views.homepage,name='homepage'),]
将文件树改为:
建立文件夹list/templates,建立文件list/templates/homepage.html
填写:
list/templates/homepage.html
<html><head> <title>To-Do lists</title></head><body> To-Do Lists are here!</body></html>
OK,喝口茶休息一下,顺便运行起来网站,进入网站看看自己的成果,并进行单元测试和功能测试
需要运行的代码有:
py -3 manage.py runserver
py -3 manage.py test
py -3 functional_test.py
没出错就可以看到这样的界面:
单元测试结果:
Creating test database for alias 'default'...System check identified no issues (0 silenced)...----------------------------------------------------------------------Ran 2 tests in 0.020sOKDestroying test database for alias 'default'...
功能测试结果:
F======================================================================FAIL: test_new_user_get_the_title (__main__.FirstTest)----------------------------------------------------------------------Traceback (most recent call last): File "functional_test.py", line 18, in test_new_user_get_the_title self.fail('Finish the Test')AssertionError: Finish the Test----------------------------------------------------------------------Ran 1 test in 47.767sFAILED (failures=1)
恩,完成了重要的一步:静态的页面。
那么解释下咱们做了什么:
1、编写单元测试,单元测试使用django自带的TestCase,测试内容为,第一个函数测试url,即网址是否正确。resolve(“/”)解析网站根路径调用的函数,判断其是否是views中的homepage函数。第二个函数测试网页中是否有必要的内容包括html标志和题目。
2、编写views,views是最重要的视图模块,几乎所有的功能性函数都在这个模块中。这次咱们设定当请求homepage函数的时候返回homepage.html。当然此时还没有编写templates,有报错正常。
3、编写url。url.py是网站的交通灯,当用户发出访问或其他请求时就是此文件到后台请求views中的函数。 url(r'^$',views.homepage,name='homepage')
,其中r'^$'
为正则表达式,表示当请求的url符合此正则表达式时,调用views.homepage
函数,他在html中的名字就是‘homepage’。
4、增加模板文件夹和第一个模板“homepage.html”。模板是显示你想要用户看到的东西的唯一方法。
接下来,我们将学习如何显示你输入的内容。
第二步 编写一个自己可用的待办事项网站
首先仍是要编写功能测试,你需要设计一个使用他的用户,让他模拟使用网站:
仍然从功能测试开始:
删除test_new_user_get_the_title
函数,添加如下函数:
from selenium.webdriver.common.keys import Keysimport time def test_can_start_a_list_and_retrieve_it_later(self): self.browser.get('http://localhost:8000') #he find 'To-Do' in the title of the web and homepage self.assertIn('To-Do',self.browser.title) header_text=self.browser.find_element_by_id('header_text').text self.assertIn('To-Do',self.browser.title) #he find a inputbox and enter two to-do lists inputbox1=self.browser.find_element_by_id('id_new_item') self.assertEqual( inputbox1.get_attribute('placeholder'), 'Enter a to-do item' ) inputbox1.send_keys('Buy a book') inputbox1.send_keys(Keys.ENTER) self.check_for_row_in_list_table('1: Buy a book') time.sleep(5) inputbox2=self.browser.find_element_by_id('id_new_item') self.assertEqual( inputbox2.get_attribute('placeholder'), 'Enter a to-do item' ) inputbox2.send_keys('Buy another book') inputbox2.send_keys(Keys.ENTER) time.sleep(5) self.check_for_row_in_list_table('1: Buy a book') self.check_for_row_in_list_table('2: Buy another book') self.fail('Finish the test') def check_for_row_in_list_table(self,row_text): table=self.browser.find_element_by_id('id_list_table') rows=table.find_elements_by_tag_name('td') self.assertIn(row_text,[row.text for row in rows])
运行出错,毫无疑问
ERROR: test_can_start_a_list_and_retrieve_it_later (__main__.FirstTest)----------------------------------------------------------------------Traceback (most recent call last): ...selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [id="header_text"]
修改tests.py中的test_homepage_return_correct_html。用更优秀的方法判断是否返回正确的html:
from django.template.loader import render_to_string def test_homepage_return_correct_html(self): request=HttpRequest() response=homepage(request) expect_html=render_to_string('homepage.html') self.assertEqual(response.content.decode(),expect_html)
修改template中的homepage:
<body> <h1 id="header_text">A To-Do List</h1> <form method="post"> <input id="id_new_item" type="text" placeholder="Enter a to-do item" name="item_text"> {% csrf_token %} </form> <table id="id_list_table"> {% for list in lists %} <tr><td>{{ forloop.counter }}: {{ list.text }}</td></tr> {% endfor %} </table></body>
修改models.html:
class Item(models.Model): text=models.TextField(max_length=20)
修改视图:views.py
from django.shortcuts import render,redirectfrom list.models import Itemdef homepage(request): if request.method=='POST': Item.objects.create(text=request.POST['item_text']) return redirect('/') lists=Item.objects.all() return render(request,'homepage.html',{'lists':lists})
同步数据库:使用命令:
py -3 manage.py makemigrationspy -3 manage.py migrate --noinput
运行django:
py -3 manage.py runserver
可以看到:
好吧,没有什么jdkfkjdf还是dfdfdf,随便输入一些东西,enter一下就可以看到了。
再进行单元测试:
py -3 manage.py test
F.======================================================================FAIL: test_homepage_return_correct_html (list.tests.HomepageTest)----------------------------------------------------------------------Traceback (most recent call last): File "G:\hhhh\list\tests.py", line 18, in test_homepage_return_correct_html self.assertEqual(response.content.decode(),expect_html)AssertionError: '<htm[226 chars] <input type=\'hidden\' name=\'csrfmiddlew[169 chars]tml>' != '<htm[226 chars] \n </form>\n\n <table id="id_list_t[40 chars]tml>'----------------------------------------------------------------------Ran 2 tests in 0.063sFAILED (failures=1)Destroying test database for alias 'default'...
?怎么可能?、
原来是csrf_token捣的鬼。
{% csrf_token %}这是为了防止 跨站请求伪造:CSRF (一种安全漏洞)
django通过针对csrf的保护措施是在生成的每个表单中放置一个自动生成的令牌,通过令牌判断POST请求是否来自同一个网站。
先注释掉csrf吧。
Creating test database for alias 'default'...System check identified no issues (0 silenced)...----------------------------------------------------------------------Ran 2 tests in 0.009sOKDestroying test database for alias 'default'...
这下ok了,然后进行功能测试。
这里说下,适时使用:
删除数据库db.sqlite3,然后运行py -3 manage.py migrate –noinput
适时调整功能测试中time.sleep(n)中n的值。
以完成功能测试。
咱们的to-do list网站第一步完成。
- 简单的待办事项清单网站--实现基本功能
- 简单的待办事项清单网站--准备工作
- React+Redux实现简单的待办事项列表ToDoList
- React+Redux实现简单的待办事项列表ToDoList
- 为什么待办事项清单不管用
- 关于基于流程的待办事项的实现
- Vuex 模块化实现待办事项的状态管理
- Vuex 模块化实现待办事项的状态管理
- Vuex 模块化实现待办事项的状态管理
- Vuex 模块化实现待办事项的状态管理
- Vuex 模块化实现待办事项的状态管理
- Vuex 模块化实现待办事项的状态管理
- 待办事项
- 待办事项
- Nodejs完成一个待办事项的实例教程
- 待办事项管理
- 待办事项不靠谱
- 随时插入待办事项的todonotes宏包
- Ubuntu 下实现FTP服务器,SSH服务器,邮件服务器,Web服务器(二)
- Linux:常用键盘快捷键
- map
- Opencv学习笔记(一) Eclispe上配置opencv
- python编码错误UnicodeDecodeError: ‘ascii’/'utf-8′ codec can’t decode byte 0xb8 in position 50: ord
- 简单的待办事项清单网站--实现基本功能
- 基于哈夫曼编码的文件压缩
- Java入门之编程基础(一)
- Xamarin android 使用RecyclerView结合SwipeRefreshLayout下拉刷新滑到底部加载更多
- 三栏布局:浮动布局、绝对布局、(相对)圣杯布局、双飞翼布局、中间固定两边自适应总结
- atitit 常见个人与企业与组织机构的信息化.docx
- java学习初探十三之集合—List详解
- Atititi atiitt eam pam资产管理 购物表去年.xlsx
- 牛客网-剑指offer-17-树的子结构