欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳盡講述用Python的Django框架測(cè)試驅(qū)動(dòng)開發(fā)的教程

 更新時(shí)間:2015年04月22日 12:16:01   投稿:goldensun  
這篇文章主要介紹了詳盡講述用Python的Django框架測(cè)試驅(qū)動(dòng)開發(fā)的教程,主要使用TDD工具,全文介紹非常詳細(xì),需要的朋友可以參考下

測(cè)試驅(qū)動(dòng)開發(fā)(TDD)是一個(gè)迭代的開發(fā)周期,強(qiáng)調(diào)編寫實(shí)際代碼之前編寫自動(dòng)化測(cè)試。

這個(gè)過(guò)程很簡(jiǎn)單:

  1.     先編寫測(cè)試。
  2.     查看測(cè)試失敗的地方
  3.     編寫足夠的代碼以使測(cè)試通過(guò)。
  4.     再次測(cè)試。
  5.     代碼重構(gòu) 。
  6.     重復(fù)以上操作。

2015422121310993.png (407×401)

為什么要用TDD?

使用TDD,你將學(xué)會(huì)把你的代碼拆分成符合邏輯的,簡(jiǎn)單易懂的片段,這有助于確保代碼的正確性。

這一點(diǎn)非常重要,因?yàn)樽龅较旅孢@些事情是非常困難的:

  •     在我們的腦中一次性處理所有復(fù)雜的問題。
  •     了解何時(shí)從哪里開始著手解決問題。
  •     在代碼庫(kù)的復(fù)雜度不斷增長(zhǎng)的同時(shí)不引入錯(cuò)誤和bug;并且
  •     辨別出代碼在什么時(shí)候發(fā)生了問題。

TDD幫助我們定位問題。它不能保證你的代碼完全沒有錯(cuò)誤;然而,你可以寫出更好的代碼,從而能更好地理解理解代碼。這本身有助于消除錯(cuò)誤,并且至少,你可以更容易的定位錯(cuò)誤。

TTD實(shí)際上也是一種行業(yè)標(biāo)準(zhǔn)。

說(shuō)的夠多了。讓我們來(lái)看看代碼吧。

在這個(gè)教程里,我們將創(chuàng)建一個(gè)存儲(chǔ)用戶聯(lián)系人的app。

請(qǐng)注意: 這篇教程假設(shè)你運(yùn)行在一個(gè)基于Unix的環(huán)境里 - 例如, Mac OSX, Linux, 或者在Windows下的Linux VM。 我將使用Sublime 2作為文本編輯器。并且,確保你已經(jīng)完成了官方的Django教程并且基本了解Python語(yǔ)言. 此外,在這個(gè)第一篇post里,我們不會(huì)涉及到Django1.6提供的新工具。這篇文章將為之后的post打好基礎(chǔ)來(lái)處理不同形式的測(cè)試。

第一個(gè)測(cè)試

在開始做一些事情之前,我們需要首先創(chuàng)建一個(gè)測(cè)試。為了這個(gè)測(cè)試,我們需要讓Django正確安裝。為此我們將使用一個(gè)函數(shù)測(cè)試——這在下面會(huì)詳細(xì)解釋。

    創(chuàng)建一個(gè)新目錄存放你的項(xiàng)目:
   

  $ mkdir django-tdd
  $ cd django-tdd

    再建立一個(gè)目錄存放函數(shù)測(cè)試
 
     

  $ mkdir ft
  $ cd ft

    創(chuàng)建一個(gè)新文件 "tests.py"并加入以下代碼:
 

  from selenium import webdriver
   
  browser = webdriver.Firefox()browser.get('http://localhost:8000/')body = browser.find_element_by_tag_name('body')assert 'Django' in body.text
   
  browser.quit()

    現(xiàn)在運(yùn)行測(cè)試:
   

  $ python tests.py

        確認(rèn)安裝selenium(譯注:自動(dòng)化測(cè)試軟件)時(shí)是使用 installed -pip安裝的

    你將看到 FireFox彈出來(lái)試圖打開 http://localhost:8000/。在你的終端上面你會(huì)看到:
   
  

 Traceback (most recent call last):File "tests.py", line 7, in <module>assert 'Django' in body.textAssertionError

    祝賀!你完成了第一個(gè)失效測(cè)試。

    現(xiàn)在我們寫足夠的代碼來(lái)讓它通過(guò),這些代碼量約相當(dāng)于設(shè)置一個(gè) Django 開發(fā)環(huán)境。


設(shè)置Django

1. 激活一個(gè)virtualenv:
 

$ cd ..
$ virtualenv --no-site-packages env
$ source env/bin/activate

2. 安裝Django并且建立一個(gè)項(xiàng)目
 

$ pip install django==1.6.1$ django-admin.py startproject contacts

你當(dāng)前的項(xiàng)目結(jié)構(gòu)應(yīng)該是下面這個(gè)樣子:

 

復(fù)制代碼 代碼如下:

├── contacts
│   ├── contacts
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── manage.py
└── ft   
    └── tests.py

3. 安裝 Selenium:
 

pip install selenium==2.39.0

4. 運(yùn)行server
 

$ cd contacts
$ python manage.py runserver

5. 接著,打開一個(gè)新終端窗口,定位到"ft"文件夾下,再運(yùn)行一次測(cè)試:
 
$ python tests.py

你將看到FireFox又一次窗口導(dǎo)航到了http://localhost:8000/。這次應(yīng)該沒有錯(cuò)誤了。你剛剛已經(jīng)通過(guò)了你的第一個(gè)測(cè)試!現(xiàn)在,讓我們完成環(huán)境設(shè)置。

6. 版本控制,首先添加一個(gè)".gitignore"并且在里面添加下面的代碼:
 

復(fù)制代碼 代碼如下:

.Pythonenv
bin
lib
include.DS_Store.pyc

現(xiàn)在來(lái)創(chuàng)建一個(gè)Git倉(cāng)庫(kù)然后提交吧

$ git init
$ git add .$ git commit -am "initial"

7. 項(xiàng)目建完了,現(xiàn)在我們回頭討論一下功能測(cè)試吧。

功能測(cè)試

我們通過(guò)用 Selenium 來(lái)進(jìn)行第一次測(cè)試。這樣的測(cè)試會(huì)使我們使用web瀏覽器就像我們是最終用戶一樣,來(lái)看看應(yīng)用程序?qū)嶋H上是怎么運(yùn)行的。因?yàn)檫@些測(cè)試是遵循最終用戶的行為習(xí)慣——也可以說(shuō)是用戶用例——這個(gè)包含了對(duì)一系列產(chǎn)品特點(diǎn)進(jìn)行測(cè)試,而不僅僅對(duì)單一功能進(jìn)行測(cè)試——這種更適合單元測(cè)試。有一點(diǎn)非常需要注意的是,當(dāng)這部分測(cè)試代碼你還沒開始寫,那么你必須先從功能測(cè)試開始。由于我們基本上是測(cè)試Django的代碼,所以功能測(cè)試是一個(gè)正確的方法去做的。

    另一種方式去思考功能測(cè)試和單元測(cè)試的區(qū)別,就是功能測(cè)試主要關(guān)注在應(yīng)用程序的外部,從用戶的角度來(lái)進(jìn)行測(cè)試,而單元測(cè)試主要是關(guān)注在應(yīng)用程序的內(nèi)部,從開發(fā)的角度進(jìn)行測(cè)試。

在實(shí)踐中會(huì)更多地體現(xiàn)這個(gè)概念。

在繼續(xù)下個(gè)話題之前,我們先來(lái)重構(gòu)我們的測(cè)試環(huán)境,使得測(cè)試起來(lái)更加簡(jiǎn)單。

    首先,我們要重寫在“tests.py”文件內(nèi)的第一個(gè)測(cè)試:
   
  

 from selenium import webdriverfrom selenium.webdriver.common.keys import Keysfrom django.test import LiveServerTestCaseclass AdminTest(LiveServerTestCase):
   
   def setUp(self):
     self.browser = webdriver.Firefox()
   
   def tearDown(self):
     self.browser.quit()
   
   def test_admin_site(self):  
     # user opens web browser, navigates to admin page
     self.browser.get(self.live_server_url + '/admin/')
     body = self.browser.find_element_by_tag_name('body')
     self.assertIn('Django administration', body.text)

    然后運(yùn)行它:
  

  $ python manage.py test ft

    它會(huì)通過(guò):
    

  ----------------------------------------------------------------------Ran 1 test in 3.304sOK

    恭喜你!

    在繼續(xù)之前,我們先看看這里是怎么回事。如果所有都通過(guò)了,你也會(huì)看到FireFox瀏覽器被打開,然后按照我們?cè)跍y(cè)試?yán)锼玫膕etUp()和tearDown()方法設(shè)置的功能進(jìn)行整個(gè)過(guò)程。這個(gè)測(cè)試本身只是簡(jiǎn)單的測(cè)試這個(gè)"/admin" (self.browser.get(self.live_server_url + '/admin/')頁(yè)面是否被找到,"Django administration"這個(gè)單詞是否出現(xiàn)在body標(biāo)簽內(nèi)。

    讓我們確認(rèn)一下。

    運(yùn)行服務(wù):
    

  $ python manage.py runserver

    在地址欄里敲上地址 http://localhost:8000/admin/ 你會(huì)看到:

2015422121333572.png (862×399)

        我們可以只需對(duì)錯(cuò)誤的東西進(jìn)行簡(jiǎn)單地測(cè)試便能確認(rèn)測(cè)試是否正確運(yùn)作。更新測(cè)試?yán)锏淖詈笠恍校?br />    

  self.assertIn('administration Django', body.text)

    重新再運(yùn)行一次。你會(huì)發(fā)現(xiàn)有以下的錯(cuò)誤(當(dāng)然是我們所期望的):
    

  AssertionError: 'administration Django' not found in u'Django administration\nUsername:\nPassword:\n '

    修正測(cè)試,再測(cè)試一遍,就可以提交代碼了。

    最后,你有沒有注意到,我們用來(lái)進(jìn)行實(shí)際測(cè)試的功能名稱均以test_開頭。這是為了讓Django測(cè)試運(yùn)行器能找到這些測(cè)試。換句話來(lái)說(shuō),任何一個(gè)以test_開頭命名的功能都會(huì)被測(cè)試運(yùn)行器視為一個(gè)測(cè)試。


管理員登陸

接下來(lái),讓我們來(lái)測(cè)試,以確保用戶可以登錄到管理網(wǎng)站。

    更新“tests.py”文件中的test_admin_site功能:

   
 

  def test_admin_site(self):  
   # user opens web browser, navigates to admin page
   self.browser.get(self.live_server_url + '/admin/')
   body = self.browser.find_element_by_tag_name('body')
   self.assertIn('Django administration', body.text)
   # users types in username and passwords and presses enter
   username_field = self.browser.find_element_by_name('username')
   username_field.send_keys('admin')
   password_field = self.browser.find_element_by_name('password')
   password_field.send_keys('admin')
   password_field.send_keys(Keys.RETURN)
   # login credentials are correct, and the user is redirected to the main admin page
   body = self.browser.find_element_by_tag_name('body')
   self.assertIn('Site administration', body.text)

    所以 -

    find_element_by_name- 是用于定位輸入框。

    send_keys- 發(fā)送鍵盤按鍵信息。

    運(yùn)行測(cè)試,你會(huì)發(fā)現(xiàn)這個(gè)錯(cuò)誤:
 
     
 

  AssertionError: 'Site administration' not found in u'Django administration\nPlease enter the correct username and password for a staff account. Note that both fields may be case-sensitive.\nUsername:\nPassword:\n '

    這個(gè)之所以會(huì)失敗,是因?yàn)槲覀儧]有管理員用戶設(shè)置。這是一個(gè)預(yù)期中的失敗,所以出現(xiàn)這種情況是對(duì)的。換句話來(lái)說(shuō),我們知道它會(huì)失敗的,這使得我們更容易去解決它。

    同步數(shù)據(jù)庫(kù):
   

  $ python manage.py syncdb

    設(shè)置一個(gè)管理員用戶。

    再重新測(cè)試一遍。它依舊會(huì)失敗。為什么呢?因?yàn)镈jango在運(yùn)行的時(shí)候會(huì)給我們數(shù)據(jù)庫(kù)創(chuàng)建一份副本,這樣的測(cè)試方式不會(huì)影響生產(chǎn)數(shù)據(jù)庫(kù)。

    我們需要設(shè)置一個(gè)Fixture,是一個(gè)包含了我們想加載到測(cè)試數(shù)據(jù)庫(kù)的數(shù)據(jù)文件:登錄憑據(jù)。為了要實(shí)現(xiàn)這一點(diǎn),當(dāng)運(yùn)行以下命令時(shí),能夠?qū)?shù)據(jù)庫(kù)管理員用戶信息從數(shù)據(jù)庫(kù)轉(zhuǎn)存到Fixture中去:
   

  $ mkdir ft/fixtures
  $ python manage.py dumpdata auth.User --indent=2 > ft/fixtures/admin.json

    現(xiàn)在更新AdminTest類:

 
  class AdminTest(LiveServerTestCase):
   
    # load fixtures
   fixtures = ['admin.json']
   
   def setUp(self):
     self.browser = webdriver.Firefox()
   
   def tearDown(self):
     self.browser.quit()
   
   def test_admin_site(self):  
     # user opens web browser, navigates to admin page
     self.browser.get(self.live_server_url + '/admin/')
     body = self.browser.find_element_by_tag_name('body')
     self.assertIn('Django administration', body.text)
     # users types in username and passwords and presses enter
     username_field = self.browser.find_element_by_name('username')
     username_field.send_keys('admin')
     password_field = self.browser.find_element_by_name('password')
     password_field.send_keys('admin')
     password_field.send_keys(Keys.RETURN)
     # login credentials are correct, and the user is redirected to the main admin page
     body = self.browser.find_element_by_tag_name('body')
     self.assertIn('Site administration', body.text)

    運(yùn)行這個(gè)測(cè)試,它會(huì)通過(guò)。

        每次運(yùn)行測(cè)試的時(shí)候,Django都會(huì)轉(zhuǎn)存測(cè)試數(shù)據(jù)庫(kù)。而這所有的Fixture都會(huì)在“test.py”文件中被指定加載到數(shù)據(jù)庫(kù)中去。

    讓我們加一個(gè)或多個(gè)斷言。再次更新測(cè)試:
 
  

 def test_admin_site(self):  
    # user opens web browser, navigates to admin page
    self.browser.get(self.live_server_url + '/admin/')
    body = self.browser.find_element_by_tag_name('body')
    self.assertIn('Django administration', body.text)
    # users types in username and passwords and presses enter
    username_field = self.browser.find_element_by_name('username')
    username_field.send_keys('admin')
    password_field = self.browser.find_element_by_name('password')
    password_field.send_keys('admin')
    password_field.send_keys(Keys.RETURN)
    # login credentials are correct, and the user is redirected to the main admin page
    body = self.browser.find_element_by_tag_name('body')
    self.assertIn('Site administration', body.text)
    # user clicks on the Users link
    user_link = self.browser.find_elements_by_link_text('Users')
    user_link[0].click()
    # user verifies that user live@forever.com is present
    body = self.browser.find_element_by_tag_name('body')
    self.assertIn('live@forever.com', body.text)

    運(yùn)行它,它會(huì)失敗,因?yàn)槲覀冃枰砑恿硪粋€(gè)用戶到fixture文件中:

  

  [{"pk": 1, "model": "auth.user", "fields": {
   "username": "admin", 
   "first_name": "", 
   "last_name": "", 
   "is_active": true, 
   "is_superuser": true, 
   "is_staff": true, 
   "last_login": "2013-12-29T03:49:13.545Z", 
   "groups": [], 
   "user_permissions": [], 
   "password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=", 
   "email": "ad@min.com", 
   "date_joined": "2013-12-29T03:49:13.545Z"}},{"pk": 2, "model": "auth.user", "fields": {
   "username": "live", 
   "first_name": "", 
   "last_name": "", 
   "is_active": true, 
   "is_superuser": false, 
   "is_staff": false, 
   "last_login": "2013-12-29T03:49:13.545Z", 
   "groups": [], 
   "user_permissions": [], 
   "password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=", 
   "email": "live@forever.com", 
   "date_joined": "2013-12-29T03:49:13.545Z"}}]

再次運(yùn)行,它是會(huì)通過(guò)的。如果需要可以重構(gòu)一下這個(gè)測(cè)試?,F(xiàn)在想想還有什么可以測(cè)試?;蛟S你可以測(cè)試管理員用戶可以添加一個(gè)用戶到管理面板中,或者可以測(cè)試沒有管理員權(quán)限的人是不能進(jìn)入管理面板中。寫幾個(gè)測(cè)試,更新你的代碼,再次測(cè)試,根據(jù)需要重構(gòu)代碼。

接下來(lái),我們會(huì)添加增加聯(lián)系人應(yīng)用,不要忘了提交代碼哦!

設(shè)置聯(lián)系人應(yīng)用

    開始一個(gè)測(cè)試,添加以下功能:
  

  def test_create_contact_admin(self):  
   self.browser.get(self.live_server_url + '/admin/')
   username_field = self.browser.find_element_by_name('username')
   username_field.send_keys('admin')
   password_field = self.browser.find_element_by_name('password')
   password_field.send_keys('admin')
   password_field.send_keys(Keys.RETURN)
   # user verifies that user_contacts is present
   body = self.browser.find_element_by_tag_name('body')
   self.assertIn('User_Contacts', body.text)

    再次運(yùn)行測(cè)試,你會(huì)看到以下錯(cuò)誤:
   
     
 

  AssertionError: 'User_Contacts' not found in u'Django administration\nWelcome, admin. Change password / Log out\nSite administration\nAuth\nGroups\nAdd\nChange\nUsers\nAdd\nChange\nRecent Actions\nMy Actions\nNone available'

    這是預(yù)料之中的。

    現(xiàn)在,我們要寫足夠的代碼讓它通過(guò)。

    新建一個(gè)應(yīng)用:
    
   

 $ python manage.py startapp user_contacts

    添加到“settings.py”文件:
   

  INSTALLED_APPS = (
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'ft',
   'user_contacts',)

    在user_contacts目錄下的“admin.py”文件中添加以下代碼:
    

  from user_contacts.models import Person, Phonefrom django.contrib import admin
   
  admin.site.register(Person)admin.site.register(Phone)

    你的工程架構(gòu)會(huì)跟如下類似:
   

復(fù)制代碼 代碼如下:

    
    .├── user_contacts
     │   ├── __init__.py
     │   ├── admin.py  
     │   ├── models.py
     │   ├── tests.py
     │   └── views.py
     ├── contacts
     │   ├── __init__.py
     │   ├── settings.py
     │   ├── urls.py
     │   └── wsgi.py
     ├── ft
     │   ├── __init__.py
     │   ├── fixtures
     │   │   └── admin.json
     │   └── tests.py
     └── manage.py

    更新“models.py”:
  
   

 from django.db import modelsclass Person(models.Model):
   first_name = models.CharField(max_length = 30)
   last_name = models.CharField(max_length = 30)
   email = models.EmailField(null = True, blank = True)
   address = models.TextField(null = True, blank = True)
   city = models.CharField(max_length = 15, null = True,blank = True)
   state = models.CharField(max_length = 15, null = True, blank = True)
   country = models.CharField(max_length = 15, null = True, blank = True)
   
   def __unicode__(self):
     return self.last_name +", "+ self.first_nameclass Phone(models.Model):
   person = models.ForeignKey('Person')
   number = models.CharField(max_length=10)
   
   def __unicode__(self):
     return self.number

    再次運(yùn)行測(cè)試,你會(huì)看到:
     

  Ran 2 tests in 11.730sOK

    我們繼續(xù)下一步驟,添加測(cè)試進(jìn)去以保證管理員可以添加數(shù)據(jù):
 
     

  # user clicks on the Persons link
  persons_links = self.browser.find_elements_by_link_text('Persons')
  persons_links[0].click()
  # user clicks on the Add person link
  add_person_link = self.browser.find_element_by_link_text('Add person')
  add_person_link.click()
  # user fills out the form
  self.browser.find_element_by_name('first_name').send_keys("Michael")
  self.browser.find_element_by_name('last_name').send_keys("Herman")
  self.browser.find_element_by_name('email').send_keys("michael@realpython.com")
  self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")
  self.browser.find_element_by_name('city').send_keys("San Francisco")
  self.browser.find_element_by_name('state').send_keys("CA")
  self.browser.find_element_by_name('country').send_keys("United States")
  # user clicks the save button
  self.browser.find_element_by_css_selector("input[value='Save']").click()
  # the Person has been added
  body = self.browser.find_element_by_tag_name('body')
  self.assertIn('Herman, Michael', body.text)
  # user returns to the main admin screen
  home_link = self.browser.find_element_by_link_text('Home')
  home_link.click()
  # user clicks on the Phones link
  persons_links = self.browser.find_elements_by_link_text('Phones')
  persons_links[0].click()
  # user clicks on the Add phone link
  add_person_link = self.browser.find_element_by_link_text('Add phone')
  add_person_link.click()
  # user finds the person in the drop
  downel = self.browser.find_element_by_name("person")
  for option in el.find_elements_by_tag_name('option'):
   if option.text == 'Herman, Michael':
     option.click()
  # user adds the phone numbers
  self.browser.find_element_by_name('number').send_keys("4158888888")
  # user clicks the save button
  self.browser.find_element_by_css_selector("input[value='Save']").click()
  # the Phone has been added
  body = self.browser.find_element_by_tag_name('body')
  self.assertIn('4158888888', body.text)
  # user logs out
  self.browser.find_element_by_link_text('Log out').click()
  body = self.browser.find_element_by_tag_name('body')
  self.assertIn('Thanks for spending some quality time with the Web site today.', body.text)

這就是管理員的功能。讓我們轉(zhuǎn)過(guò)頭來(lái)專注于user_contacts本身。你之前的代碼還記得提交嗎?如果沒有,趕緊提交吧!


單元測(cè)試

考慮下我們現(xiàn)在已經(jīng)寫的特性。我們已經(jīng)定義了我們的模型,允許管理員更改模型。根據(jù)這個(gè)情況和我們項(xiàng)目的整體目標(biāo),著重關(guān)注剩下的用戶功能。

用戶應(yīng)該可以——

  •     瀏覽所有的聯(lián)系人。
  •     添加新的聯(lián)系人。

根據(jù)這些需求,嘗試把剩下的功能測(cè)試公式化。盡管,在我們寫功能測(cè)試之前,我們應(yīng)該通過(guò)單元測(cè)試定義代碼的行為——這有助于你寫出良好、干凈的代碼,編寫功能測(cè)試更加簡(jiǎn)單。

    記?。汗δ軠y(cè)試最終將表示你的項(xiàng)目是否工作,而單元測(cè)試有助于你達(dá)到這樣的目的。這很快就會(huì)變的有意義。

讓我們暫停片刻,談?wù)撘恍┏R?guī)慣例。

盡管TDD(或者終端)的基礎(chǔ)——測(cè)試、代碼、重構(gòu)——是通用的,很多開發(fā)者使用的方法是不同的。例如,我喜歡先寫單元測(cè)試,保證我們的代碼在細(xì)粒度級(jí)別有效,然后寫功能測(cè)試。其他開發(fā)者先寫功能測(cè)試,查看它們失敗,然后寫單元測(cè)試,查看它們失敗,然后再寫代碼,首先滿足單元測(cè)試,最終也應(yīng)該滿足功能測(cè)試。這里沒有正確和錯(cuò)誤的答案。哪種方法舒服用哪種——但繼續(xù)先測(cè)試、然后寫代碼,最后重構(gòu)。

視圖

首先,檢查所有視圖都設(shè)置準(zhǔn)確。
主視圖

    跟往常一樣,先開始一個(gè)測(cè)試:
    

  from django.template.loader import render_to_stringfrom django.test import TestCase, Clientfrom user_contacts.models import Person, Phonefrom user_contacts.views import *class ViewTest(TestCase):def setUp(self):
    self.client_stub = Client()def test_view_home_route(self):
    response = self.client_stub.get('/')
    self.assertEquals(response.status_code, 200)

    給這個(gè)測(cè)試文件取名為test_views.py,并保存到user_contacts/tests目錄下。同時(shí)要添加__init__.py文件到目錄中去,在user_contacts主目錄下刪除"tests.py"文件。

    運(yùn)行它:
 

  $ python manage.py test user_contacts

    它會(huì)失敗的 -AssertionError: 404 != 200- 因?yàn)閁RL、視圖和模板都還沒存在。如果你不熟悉Django如何處理MVC架構(gòu),請(qǐng)點(diǎn)擊這里閱覽這篇簡(jiǎn)短的文章。我們首先獲取用客戶端獲取url的“/”地址,這事Django的TestCase的一部分。這個(gè)響應(yīng)被存儲(chǔ)起來(lái),然后我們?nèi)z查返回的狀態(tài)碼是否等于200。

    添加如下路徑到“contacts/urls.py”:
   

復(fù)制代碼 代碼如下:

(r'^', include('user_contacts.urls')),

    更新“contacts/urls.py”:
  

  from django.conf.urls import patterns, urlfrom user_contacts.views import *urlpatterns = patterns('',
    url(r'^$', home),)

    更新“views.py”:
   

  from django.http import HttpResponse, HttpResponseRedirectfrom django.shortcuts import render_to_response, renderfrom django.template import RequestContextfrom user_contacts.models import Phone, Person# from user_contacts.new_contact_form import ContactFormdef home(request):
   return render_to_response('index.html')

    添加“index.html”模板到模板目錄中去:
  
    

 
  <!DOCTYPE html><html>
   <head>
    <title>Welcome.</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link  rel="stylesheet" media="screen">
    <style>
      .container {
        padding: 50px;
      }
    </style>
   </head>
   <body>
    <div class="container">
      <h1>What would you like to do?</h1>
      <ul>
        <li><a href="/all">View Contacts</a></li>
        <li><a href="/add">Add Contact</a></li>
      </ul>
    <div>
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
   </body></html>

    再次運(yùn)行測(cè)試,它就會(huì)順利通過(guò)。


所有聯(lián)系人視圖

對(duì)這個(gè)視圖的測(cè)試幾乎和我們上一個(gè)測(cè)試相同。在看我的答案之前先自己試試吧。

1.通過(guò)在ViewTest類里添加下面的方法來(lái)開始這個(gè)測(cè)試。
 

def test_view_contacts_route(self):
 response = self.client_stub.get('/all/')
 self.assertEquals(response.status_code, 200)

2. 在運(yùn)行時(shí),你將看到同樣的錯(cuò)誤:AssertionError: 404 != 200 。

3. 用下面的路由策略更新"user_contacts/urls.py":
 

url(r'^all/$', all_contacts),

4. 更新"view.py":
 

def all_contacts(request):
 contacts = Phone.objects.all()
 return render_to_response('all.html', {'contacts':contacts})

5. 在templates文件夾里加入一個(gè)叫"all.html"的模板:
 

<!DOCTYPE html><html><head><title>All Contacts.</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><link  rel="stylesheet" media="screen"><style>
 .container {
  padding: 50px;
 }</style></head><body><div class="container">
 <h1>All Contacts</h1>
 <table border="1" cellpadding="5">
  <tr>
   <th>First Name</th>
   <th>Last Name</th>
   <th>Address</th>
   <th>City</th>
   <th>State</th>
   <th>Country</th>
   <th>Phone Number</th>
   <th>Email</th>
  </tr>
  {% for contact in contacts %}   <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
   </tr>
  {% endfor %} </table>
 <br>
 <a href="/">Return Home</a></div><script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script></body></html>

6. 然后測(cè)試應(yīng)該能通過(guò)了。

增加聯(lián)系人視圖

這個(gè)測(cè)試與前面兩個(gè)稍有不同,所以一定要仔細(xì)的跟著下列步驟走。

1. 在test suite里加入測(cè)試:
 

def test_add_contact_route(self):
 response = self.client_stub.get('/add/')
 self.assertEqual(response.status_code, 200)

2. 你將在運(yùn)行時(shí)看到這樣的錯(cuò)誤:AssertionError: 404 != 200

3. 更新"urls.py":
 

url(r'^add/$', add),

4. 更新"views.py"
 

def add(request):person_form = ContactForm()return render(request, 'add.html', {'person_form' : person_form}, context_instance = RequestContext(request))

確保加入了如下的引用:
 
from user_contacts.new_contact_form import ContactForm

5. 創(chuàng)建一個(gè)叫 new_contact_form.py的新文件然后加入如下代碼:
 

import refrom django import formsfrom django.core.exceptions import ValidationErrorfrom user_contacts.models import Person, Phoneclass ContactForm(forms.Form):
 first_name = forms.CharField(max_length=30)
 last_name = forms.CharField(max_length=30)
 email = forms.EmailField(required=False)
 address = forms.CharField(widget=forms.Textarea, required=False)
 city = forms.CharField(required=False)
 state = forms.CharField(required=False)
 country = forms.CharField(required=False)
 number = forms.CharField(max_length=10)
 
 def save(self):
   if self.is_valid():
     data = self.cleaned_data
     person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),
       email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),
       country=data.get('country'))
     phone = Phone.objects.create(person=person, number=data.get('number'))
     return phone

6. 加入"add.html"到模板文件夾里:
 

import refrom django import formsfrom django.core.exceptions import ValidationErrorfrom user_contacts.models import Person, Phoneclass ContactForm(forms.Form):
 first_name = forms.CharField(max_length=30)
 last_name = forms.CharField(max_length=30)
 email = forms.EmailField(required=False)
 address = forms.CharField(widget=forms.Textarea, required=False)
 city = forms.CharField(required=False)
 state = forms.CharField(required=False)
 country = forms.CharField(required=False)
 number = forms.CharField(max_length=10)
 
 def save(self):
   if self.is_valid():
     data = self.cleaned_data
     person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),
       email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),
       country=data.get('country'))
     phone = Phone.objects.create(person=person, number=data.get('number'))
     return phone

7. 是不是通過(guò)了?應(yīng)該是的。如果沒有,再檢查一下。

驗(yàn)證

現(xiàn)在我們已經(jīng)完成了視圖的測(cè)試,讓我們添加對(duì)表單的驗(yàn)證。但首先我們要寫一個(gè)測(cè)試,驚喜吧!

    在“tests”目錄下新增一個(gè)叫“test_validator.py”的文件并增加以下代碼:
 

  from django.core.exceptions import ValidationError
    from django.test import TestCase
    from user_contacts.validators import validate_number, validate_string  class ValidatorTest(TestCase):
      def test_string_is_invalid_if_contains_numbers_or_special_characters(self):
        with self.assertRaises(ValidationError):
          validate_string('@test')
          validate_string('tester#')
      def test_number_is_invalid_if_contains_any_character_except_digits(self):
        with self.assertRaises(ValidationError):
          validate_number('123ABC')
          validate_number('75431#')

    在運(yùn)行測(cè)試之前,你猜猜會(huì)有什么情況發(fā)生?提示:請(qǐng)密切注意代碼上面導(dǎo)入進(jìn)來(lái)的包。你會(huì)有以下錯(cuò)誤信息,因?yàn)槲覀儧]有“validators.py”文件:
 

  ImportError: cannot import name validate_string

    換言之,我們測(cè)試所需的邏輯驗(yàn)證文件還不存在。

    在“user_contacts”目錄下新增一個(gè)叫“validators.py”的文件:
  

  import refrom django.core.exceptions import ValidationErrordef validate_string(string):
   if re.search('^[A-Za-z]+$', string) is None:
     raise ValidationError('Invalid')def validate_number(value):
   if re.search('^[0-9]+$', value) is None:
     raise ValidationError('Invalid')

    再次運(yùn)行測(cè)試。5個(gè)測(cè)試會(huì)通過(guò)的:
  

  Ran 5 tests in 0.019sOK

新增聯(lián)系人

    由于我們?cè)黾恿蓑?yàn)證,我們想測(cè)試一下在管理員區(qū)域這個(gè)驗(yàn)證功能是可以工作的,所以更新“test_views.py”:

     
  

 from django.template.loader import render_to_stringfrom django.test import TestCase, Clientfrom user_contacts.models import Person, Phonefrom user_contacts.views import *class ViewTest(TestCase):
   def setUp(self):
     self.client_stub = Client()
     self.person = Person(first_name = 'TestFirst',last_name = 'TestLast')
     self.person.save()
     self.phone = Phone(person = self.person,number = '7778889999')
     self.phone.save()
   def test_view_home_route(self):
     response = self.client_stub.get('/')
     self.assertEquals(response.status_code, 200)
   def test_view_contacts_route(self):
     response = self.client_stub.get('/all/')
     self.assertEquals(response.status_code, 200)
   def test_add_contact_route(self):
     response = self.client_stub.get('/add/')
     self.assertEqual(response.status_code, 200)
   def test_create_contact_successful_route(self):
     response = self.client_stub.post('/create',data = {'first_name' : 'testFirst', 'last_name':'tester', 'email':'test@tester.com', 'address':'1234 nowhere', 'city':'far away', 'state':'CO', 'country':'USA', 'number':'987654321'})
     self.assertEqual(response.status_code, 302)
   def test_create_contact_unsuccessful_route(self):
     response = self.client_stub.post('/create',data = {'first_name' : 'tester_first_n@me', 'last_name':'test', 'email':'tester@test.com', 'address':'5678 everywhere', 'city':'far from here', 'state':'CA', 'country':'USA', 'number':'987654321'})
     self.assertEqual(response.status_code, 200)
   def tearDown(self):
     self.phone.delete()
     self.person.delete()

    兩個(gè)測(cè)試會(huì)失敗。

    我們要怎么做才能讓測(cè)試通過(guò)呢?首先我們要為添加數(shù)據(jù)到數(shù)據(jù)庫(kù)增加一個(gè)視圖功能來(lái)查看。

    添加路徑:
 

  url(r'^create$', create),

    更新“views.py”:

     

  def create(request):
   form = ContactForm(request.POST)if form.is_valid():
    form.save()
    return HttpResponseRedirect('all/')return render(request, 'add.html', {'person_form' : form}, context_instance = RequestContext(request))

    再次測(cè)試:
    

  $ python manage.py test user_contacts

    這次只有一個(gè)測(cè)試會(huì)失敗 - AssertionError: 302 != 200 - 因?yàn)槲覀儑L試添加一些不通過(guò)驗(yàn)證的數(shù)據(jù)但添加成功了。換言之,我們需要更新“models.py”文件中的表單都要把驗(yàn)證考慮進(jìn)去。

    更新“models.py”:
 

 

  from django.db import modelsfrom user_contacts.validators import validate_string, validate_numberclass Person(models.Model):
    first_name = models.CharField(max_length = 30, validators = [validate_string])
    last_name = models.CharField(max_length = 30, validators = [validate_string])
    email = models.EmailField(null = True, blank = True)
    address = models.TextField(null = True, blank = True)
    city = models.CharField(max_length = 15, null = True,blank = True)
    state = models.CharField(max_length = 15, null = True, blank = True, validators = [validate_string])
    country = models.CharField(max_length = 15, null = True, blank = True)
   
    def __unicode__(self):
      return self.last_name +", "+ self.first_nameclass Phone(models.Model):
    person = models.ForeignKey('Person')
    number = models.CharField(max_length=10, validators = [validate_number])
   
    def __unicode__(self):
      return self.number

    刪除當(dāng)前的數(shù)據(jù)庫(kù),“db.sqlite3”,重新同步數(shù)據(jù)庫(kù):
   
   

 $ python manage.py syncdb

    再次設(shè)置一個(gè)管理員賬戶。

    新增驗(yàn)證,更新new_contact_form.py:

  

 import refrom django import formsfrom django.core.exceptions import ValidationErrorfrom user_contacts.models import Person, Phonefrom user_contacts.validators import validate_string, validate_numberclass ContactForm(forms.Form):
   first_name = forms.CharField(max_length=30, validators = [validate_string])
   last_name = forms.CharField(max_length=30, validators = [validate_string])
   email = forms.EmailField(required=False)
   address = forms.CharField(widget=forms.Textarea, required=False)
   city = forms.CharField(required=False)
   state = forms.CharField(required=False, validators = [validate_string])
   country = forms.CharField(required=False)
   number = forms.CharField(max_length=10, validators = [validate_number])
   def save(self):
     if self.is_valid():
       data = self.cleaned_data
       person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),
         email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),
         country=data.get('country'))
       phone = Phone.objects.create(person=person, number=data.get('number'))
       return phone

    再次運(yùn)行測(cè)試,7個(gè)測(cè)試會(huì)通過(guò)的。

    現(xiàn)在,先脫離開TDD一會(huì)兒。我想在客戶端添加一個(gè)額外的測(cè)試驗(yàn)證。所以添加test_contact_form.py:

     
    

from django.test import TestCasefrom user_contacts.models import Personfrom user_contacts.new_contact_form import ContactFormclass TestContactForm(TestCase):
   def test_if_valid_contact_is_saved(self):
     form = ContactForm({'first_name':'test', 'last_name':'test','number':'9999900000'})
     contact = form.save()
     self.assertEqual(contact.person.first_name, 'test')
   def test_if_invalid_contact_is_not_saved(self):
     form = ContactForm({'first_name':'tes&t', 'last_name':'test','number':'9999900000'})
     contact = form.save()
     self.assertEqual(contact, None)

    運(yùn)行測(cè)試,所有9個(gè)測(cè)試都通過(guò)了。耶!現(xiàn)在可以提交代碼了。

功能測(cè)試的終極版

當(dāng)單元測(cè)試已經(jīng)完成了,我們現(xiàn)在添加功能測(cè)試去保證應(yīng)用程序可以順利運(yùn)行。但愿由于我們的單元測(cè)試已經(jīng)通過(guò)了,功能測(cè)試也不會(huì)有什么問題。

    添加一個(gè)新類到“tests.py”文件中:
 
  

 class UserContactTest(LiveServerTestCase):
   
   def setUp(self):
     self.browser = webdriver.Firefox()
     self.browser.implicitly_wait(3)
   
   def tearDown(self):
     self.browser.quit()
   
   def test_create_contact(self): 
     # user opens web browser, navigates to home page  
     self.browser.get(self.live_server_url + '/')
     # user clicks on the Persons link
     add_link = self.browser.find_elements_by_link_text('Add Contact')
     add_link[0].click()
     # user fills out the form
     self.browser.find_element_by_name('first_name').send_keys("Michael")
     self.browser.find_element_by_name('last_name').send_keys("Herman")
     self.browser.find_element_by_name('email').send_keys("michael@realpython.com")
     self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")
     self.browser.find_element_by_name('city').send_keys("San Francisco")
     self.browser.find_element_by_name('state').send_keys("CA")
     self.browser.find_element_by_name('country').send_keys("United States")
     self.browser.find_element_by_name('number').send_keys("4158888888")
     # user clicks the save button
     self.browser.find_element_by_css_selector("input[value='Add']").click()
     # the Person has been added
     body = self.browser.find_element_by_tag_name('body')
     self.assertIn('michael@realpython.com', body.text)
   
   def test_create_contact_error(self): 
     # user opens web browser, navigates to home page  
     self.browser.get(self.live_server_url + '/')
     # user clicks on the Persons link
     add_link = self.browser.find_elements_by_link_text('Add Contact')
     add_link[0].click()
     # user fills out the form
     self.browser.find_element_by_name('first_name').send_keys("test@")
     self.browser.find_element_by_name('last_name').send_keys("tester")
     self.browser.find_element_by_name('email').send_keys("test@tester.com")
     self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")
     self.browser.find_element_by_name('city').send_keys("Tester City")
     self.browser.find_element_by_name('state').send_keys("TC")
     self.browser.find_element_by_name('country').send_keys("TCA")
     self.browser.find_element_by_name('number').send_keys("4158888888")
     # user clicks the save button
     self.browser.find_element_by_css_selector("input[value='Add']").click()
     body = self.browser.find_element_by_tag_name('body')
     self.assertIn('Invalid', body.text)

    運(yùn)行功能測(cè)試:
   

  $ python manage.py test ft

    這里我們只測(cè)試我們寫過(guò)的,以及從最終用戶角度來(lái)看已經(jīng)被單元測(cè)試過(guò)的代碼。4個(gè)測(cè)試都將會(huì)通過(guò)。

    最后,我們通過(guò)添加以下功能到AdminTest類來(lái)保證我們添加進(jìn)去的驗(yàn)證會(huì)應(yīng)用到管理員面板中:
   
  

 def test_create_contact_admin_raise_error(self): 
   # # user opens web browser, navigates to admin page, and logs in  
   self.browser.get(self.live_server_url + '/admin/')
   username_field = self.browser.find_element_by_name('username')
   username_field.send_keys('admin')
   password_field = self.browser.find_element_by_name('password')
   password_field.send_keys('admin')
   password_field.send_keys(Keys.RETURN)
   # user clicks on the Persons link
   persons_links = self.browser.find_elements_by_link_text('Persons')
   persons_links[0].click()
   # user clicks on the Add person link
   add_person_link = self.browser.find_element_by_link_text('Add person')
   add_person_link.click()
   # user fills out the form
   self.browser.find_element_by_name('first_name').send_keys("test@")
   self.browser.find_element_by_name('last_name').send_keys("tester")
   self.browser.find_element_by_name('email').send_keys("test@tester.com")
   self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")
   self.browser.find_element_by_name('city').send_keys("Tester City")
   self.browser.find_element_by_name('state').send_keys("TC")
   self.browser.find_element_by_name('country').send_keys("TCA")
   # user clicks the save button
   self.browser.find_element_by_css_selector("input[value='Save']").click()
   body = self.browser.find_element_by_tag_name('body')
   self.assertIn('Invalid', body.text)

    運(yùn)行它。會(huì)有5個(gè)測(cè)試通過(guò)。提交之后就可以收工啦。


測(cè)試結(jié)構(gòu)

TDD是一個(gè)強(qiáng)大的工具以及是開發(fā)周期的一部分,幫助開發(fā)人員將程序拆分成小的、可讀性強(qiáng)的部分。這樣的組成部分可以更容易編寫和修改。另外,有一套全面完整的測(cè)試組件,覆蓋了你代碼的所有功能,有助于確保新功能在實(shí)現(xiàn)的時(shí)候不會(huì)破壞現(xiàn)有的功能。

在這過(guò)程中,功能測(cè)試是一個(gè)高層次的測(cè)試,重點(diǎn)放在了最終用戶的交互功能上。

同時(shí),單元測(cè)試支持功能測(cè)試來(lái)測(cè)試代碼的每個(gè)功能。請(qǐng)記住,因?yàn)閱卧獪y(cè)試一次僅需測(cè)一個(gè)產(chǎn)品特征,所以它們更容易編寫,一般覆蓋性會(huì)更好些,也更容易調(diào)試。它們會(huì)運(yùn)行非???,所以你進(jìn)行單元測(cè)試的次數(shù)往往會(huì)多于功能測(cè)試。

讓我們來(lái)看看我們的測(cè)試結(jié)構(gòu),看看我們的單元測(cè)試是如何支持功能測(cè)試的:

2015422121427964.png (982×304)

總結(jié)

恭喜你,你完成了!接下來(lái)做什么呢?

首先,我沒有100%地遵循TDD過(guò)程,這是沒有關(guān)系的。大部分用TDD進(jìn)行開發(fā)的開發(fā)人員并不會(huì)始終堅(jiān)持在每一個(gè)情況下都使用它。有時(shí)候,你為了把事情做好而偏離它這個(gè)過(guò)程——這是完全沒有問題的。如果你想重構(gòu)代碼、過(guò)程使得它更好地遵循TDD過(guò)程,你也可以這么去做。事實(shí)上,這是一個(gè)很好的做法。

其次,思考一下我錯(cuò)過(guò)的測(cè)試。確定什么地方以及什么時(shí)候去測(cè)試是困難的。這一般需要時(shí)間和大量的練習(xí)去把測(cè)試做好。我打算在我的下一篇文章中多留一些空白,來(lái)看看你們能否找到那些空白并添加測(cè)試。

最后,還記得TDD過(guò)程的最后一步嗎?這一步是至關(guān)重要的,因?yàn)樗梢詭椭鷦?chuàng)建可讀性強(qiáng)的、可維護(hù)的代碼,你不僅僅要現(xiàn)在理解這件事,在將來(lái)也要如此。當(dāng)你重新看回你的代碼,思考下你結(jié)合起來(lái)的測(cè)試。此外,你應(yīng)該添加哪些測(cè)試來(lái)確保所有寫過(guò)的代碼都被測(cè)試?例如你可以測(cè)試空值或者服務(wù)端的驗(yàn)證。你也可以在準(zhǔn)備寫新代碼前去重構(gòu)之前沒時(shí)間去整理的代碼?;蛟S這是另外一篇博文?思考下糟糕的代碼如何污染整個(gè)過(guò)程?

感謝閱讀。點(diǎn)擊這里獲取最終的代碼。有任何的問題請(qǐng)?jiān)谙旅嬖u(píng)論。

相關(guān)文章

  • django fernet fields字段加密實(shí)踐詳解

    django fernet fields字段加密實(shí)踐詳解

    這篇文章主要介紹了django fernet fields字段加密實(shí)踐詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • python使用7z解壓軟件備份文件腳本分享

    python使用7z解壓軟件備份文件腳本分享

    這篇文章主要介紹了python使用7z解壓軟件備份文件腳本,需要的朋友可以參考下
    2014-02-02
  • 使用Jupyter notebooks上傳文件夾或大量數(shù)據(jù)到服務(wù)器

    使用Jupyter notebooks上傳文件夾或大量數(shù)據(jù)到服務(wù)器

    這篇文章主要介紹了使用Jupyter notebooks上傳文件夾或大量數(shù)據(jù)到服務(wù)器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04
  • Python3使用turtle繪制超立方體圖形示例

    Python3使用turtle繪制超立方體圖形示例

    這篇文章主要介紹了Python3使用turtle繪制超立方體圖形,結(jié)合實(shí)例形式分析了Python使用海龜繪圖模塊turtle進(jìn)行復(fù)雜圖形繪制的相關(guān)原理與操作技巧,需要的朋友可以參考下
    2018-06-06
  • Python初識(shí)邏輯與if語(yǔ)句及用法大全

    Python初識(shí)邏輯與if語(yǔ)句及用法大全

    這篇文章主要介紹了Python初識(shí)邏輯與if語(yǔ)句,文中給大家提到了if語(yǔ)句功能及用法講解,需要的朋友可以參考下
    2021-08-08
  • Python3.5以上版本lxml導(dǎo)入etree報(bào)錯(cuò)的解決方案

    Python3.5以上版本lxml導(dǎo)入etree報(bào)錯(cuò)的解決方案

    這篇文章主要介紹了Python3.5以上版本lxml導(dǎo)入etree報(bào)錯(cuò)的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-06-06
  • python中pop()函數(shù)的語(yǔ)法與實(shí)例

    python中pop()函數(shù)的語(yǔ)法與實(shí)例

    這篇文章主要給大家介紹了關(guān)于python中pop()函數(shù)語(yǔ)法與實(shí)例的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 淺談python的深淺拷貝以及fromkeys的用法

    淺談python的深淺拷貝以及fromkeys的用法

    這篇文章主要介紹了python的深淺拷貝以及fromkeys的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Python如何在DataFrame增加數(shù)值

    Python如何在DataFrame增加數(shù)值

    這篇文章主要介紹了Python如何在DataFrame增加數(shù)值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 基于PyQt5完成的PDF拆分功能

    基于PyQt5完成的PDF拆分功能

    這篇文章主要介紹了基于PyQt5完成的PDF拆分功能,本文介紹的pdf拆分功能還有一些待完善地方,例如可增加預(yù)覽功能,實(shí)現(xiàn)每頁(yè)預(yù)覽,以及如何實(shí)現(xiàn)多條件拆分,需要的朋友可以參考下
    2022-06-06

最新評(píng)論