简单的待办事项清单网站--实现基本功能

来源:互联网 发布:淘宝魔兽带团本 编辑:程序博客网 时间: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 listpython 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网站第一步完成。

阅读全文
0 0
原创粉丝点击