測試驅動開發模式,要求開發在寫業務代碼的時候,先寫出測試代碼,同時單元測試例子決定了如何來寫產品的代碼,而且不斷的成功的執行編寫的全部的單元測試例子,不斷的完善單元測試例子進而完善產品代碼, 這樣隨着功能的開發完成,測試代碼也會對應的完成, 很顯然,這是一個全新的開發模式, 在必定程度上,能夠徹底的提升軟件的質量,以及開發能夠對本身寫的代碼進行一個全面的評估和測試。html
TDD 模式是一個很大的概念,在這裏, 我重點介紹下測試驅動模式與自動化的融合以及精簡自動化的測試代碼。
下面咱們來看一個登陸的案例:python
coding:utf-8 import unittest from selenium import webdriver class developTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(30) self.driver.maximize_window() self.driver.get('http://xxxx/login') self.addCleanup(self.driver.quit) def testLogin(self): #用戶名輸入 name = self.driver.find_element_by_id('xxxx') name.clean() name.send_keys('xxxx') #密碼輸入 passwd = self.driver.find_element_by_id('xxxx') passwd.clear() passwd.send_keys('xxxx') #點擊登陸 self.driver.find_element_by_id('xxxx').click() #獲取到用戶暱稱 userName = self.driver.find_element_by_xpath("xxx") userlnfo = userName.text #退出系統 userName.click() self.driver.find_element_by_xpath("xxxx").click() self.assentTrue(userlnfo in 'linux') if __name__ =='__main__': unittest.main(verbosity=2)
如上的代碼, 咱們成功的實現了登陸 ,獲取到用戶的暱稱,退出系統,以及驗證用戶暱稱這樣的一個過程, 可是問題也就來了,若是我登陸系統 N 次以及退出系統次,那麼就意味着寫登陸退出就得 N次,很明顯,這樣不少的登陸退出的代碼都是一致的,增長了工做量,以下, 我經過把登陸,退出,獲取到用戶暱稱,寫成一個單獨的函數,而後使用到了直接調用對應的函數(調用的時候記得導入), 文件名稱是 kuihua.py, 具體代碼爲以下:linux
#coding:utf-8 #登陸函數 def login(driver,usenname='I59xxxxx',password='server'): driver.find_element_by_id('xxxx').send_keys(usenname) driver.find_element_by_id('xxxx').send_keys(password) driver.find_element_by_id('xxxx').click() #獲取用戶暱稱 def getName(driver): return driver.find_element_by_xpath("xxxx").text #退出系統 def exitSystem(driver): dniver.find_element_by_xpath("xxxx").click() dniver.find_element_by_xpath("xxxx").click() 如上函數以後,測試腳本就精簡不少了,測試腳本見以下: #coding:utf-8 import unittest from selenium import webdriver import kuihua class developTest(unittest.TestCase): def setUp(self): self.driver=webdriver.Firefox() self.driver.implicitly_wait(30) self.driver.maximize_window() self.driver.get('http://my.weke.com/login.html') self.addCleanup(self.driver.quit) def testLogin(self): kuihua.login(self.driver) userInfo=vke.getName(self.driver) vke.exitSystem(self.driver) self.assentTrue(usenInfo in 'linux') if __name == '__main__': unittest.main(verbosity=2)
經過這樣的一個實例, 咱們把測試腳本精簡了不少,其實還能夠把最後一步精簡下,可是我通常感受,最後一步仍是在測試代碼中比較好,所以咱們能夠總結出以下幾點:
一、 對於某些公用的功能,如登陸,退出,單獨寫成一個函數, 須要
的時候,直接調用函數;
二、 驗證點必定要寫在最後一步,本實例驗證用戶暱稱部分,不能夠寫在退出以前驗證,先獲取到用戶暱稱,退出系統,再驗證用戶暱稱
三、 儘可能保持測試腳本與頁面對象元素分離開,這樣即便系統需求變動或者開發把頁面元素更改了,咱們只在一個地方維護,而不影響 tescase 的腳本。雖然咱們實現了把測試用例的代碼精簡化, 實現了測試腳本與頁面對象的分離,實現了後期維護頁面對象只在一個地方維護,可是仍是存在不少的缺點, 咱們可不能夠把使用到的數據,頁面對象放在.csv.xml 文件中了?答案固然是能夠, 下來部分咱們重點介紹把使用到的數據放在.txt, .csv, . xlsx, xml 文件中, 同時介紹 ddt 模塊的安裝以及使用方法, 來繼續重構咱們的測試代碼。android
ddt 是 python 的第三庫, 全名稱爲: Data-Driven/Decorated Tests。ddt 模塊提供了建立數據驅動的測試,關於該模塊,建議到官方查看詳細的說明, 安裝方法分別爲命令行安裝或者下載文件進行安裝,分別進行說明,二種安裝的方式具體見以下:
一、下載ddt文件,讓後解壓,到解壓的目錄下,輸入: pythonsetup.py install 安裝,見以下的截圖:ios
二、 直接使用 pip 在線安裝 ddt, 命令爲: pip install ddtweb
在實際自動化測試中的應用,代碼以下:app
#coding:utf-8 import unittest from selenium import webdriver from ddt import ddt,data,unpack from time import sleep @ddt class developTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(30) self.driver.maximize_window() self.driver.get('http://www.baidu.com') self.addcleanup(self.driver.quit)@data(('','',u'手機/郵箱/用戶名'),('admin','',u'請您填寫密碼'),('admin','admin',u'您輸入的賬號或密碼有誤,忘記密碼?')) @unpack def testLogin(self, sendValue1, sendValue2, expected): self.driver.find_element_by_link_text(u'登陸’).click() sleep(2) #輸入百度帳號 userName=self.driver.find_element_by_id('xxxx') userName.clear() userMame.send_keys(sendValuel) #輸入百度密碼 password=self.driver.find_element_by_id('xxxxx') password.clear() password.send_keys(sendValue2) #點擊登陸按鈕 self.driver.find_element_by_id('xxxxx').click() #獲取到返回的錯誤信息 errorText=self.driver.find_element_by_xpath("xxxxx").text self.assentTrue(emonText, expected) if __name__ =='__main__': unittest.main(verbosity=2)
從如上的代碼以及執行結果的截圖,咱們能夠地獲得,這個測試用例
驗證了三個驗證點, 分別是:
一、 百度帳號爲空, 密碼爲空, 點擊登陸按鈕, 驗證返回的錯誤信息
二、 輸入百度帳號,未輸入密碼, 驗證返回的錯誤信息
三、 輸入錯誤的帳號和錯誤的密碼, 驗證返回的錯誤信息
可是咱們的核心代碼只有以下的幾行:函數
ddt 模塊的優秀之處, 幾行代碼,實現多個測試點, 能夠少寫了不少代碼。單元測試
python提供了對 csv文件處理的模塊,直接 import csv就能夠了,那麼神祕是 csv 文件了? csv 文件全名稱爲 Comma-SeparatedValues,csv 是通用的,相對簡單的文件格式,其文件已純文件形式存儲數據。 咱們把數據存儲在 csv 的文件中,而後寫一個函數獲取到 csv文件的數據, 在自動化中引用,這樣,咱們自動化中使用到的數據,就能夠直接在 csv 文件中維護了,見下面的一個 csv 文件的格式:測試
下面咱們實現讀寫 csv 文件中的數據,具體見以下實現的代碼:
爲了具體讀取到 csv 文件中某一列的數據,咱們能夠把讀取 csv 文件的方法修改以下,見代碼:
如咱們須要讀取第一個 selenium, csv 文件內容見如上的截圖,那麼調用的方法代碼爲:
執行後以下截圖:
已百度搜索輸入框爲實例,在搜索輸入框輸入 csv 文件中的字符,咱們把讀寫 csv 文件的函數寫在 location.py 的模塊中,見 location.py的源碼:
#coding:utf-8 import csv #讀取CSV的文件 def getCsv(valuel,value2,file_name='d:/test.csv'): nows=[] with open(file_name,'nb') as f: neaders=csv.reader(f,delimiters't ',quotechar='|') next(readers^None) for row in readers: rows.append(row) return rows[valuel][value2] #csv文件中寫數據 def writeCsv(file_name='d:/test.csv'): with open(file_name,'wb') as f: wnite=csv.writer(f) write.writerow(['Element','system'])data=[ ('selenium''webdriver'), ('appium','android'), ('appium','ios'), ('selenium','python')] write.writerows(data) f.close()
把測試代碼寫在 baiduTest.py 的模塊中,見該模塊的源碼:
#coding:utf-8 from selenium import webdriver import location import unittest import time time.sleep(5) class BaiduTest(unittest.TestCase): def setUp(self): self.driver=webdriver.Firefox() self.driver.maximize_window() self.driver.implicitly一wait(30) self.driver.get(location.getCsv(4,0)) def testCase_01(self): '''獲取CSV文件中第二列第_位的數據進行搜索''' self.driver.find_element_by_id('kw').send_keys(location.getCsv(l,0)) def tearDown(self): self.driver.quit() if __name__=='__main__': suite = unittest.TestLoader().loadTestsFnomTestCase(BaiduTest) unittest.TextTestRunner(verbosity=2).run(suite)
在如上的測試代碼中,我把 url,以及搜索的字符都放在了 csv 的文件中,在測試腳本中,只須要調用讀取 csv 文件的函數,這樣,咱們就能夠實現了把測試使用到的數據存儲在 csv 的文件中,來進行處理。
在前面我這邊介紹到了 ddt 的模塊,那麼如今我這邊 ddt 模塊和csv 文件結合,來進行自動化的測試,編輯後的 csv 文件後:
我從新寫 location.py 的模塊,具體見該模塊的源碼:
#coding:utf-8 import csv def getCsv(file_name): rows=[] with open(file_name, 'rb') as f: readers = csv.reader(f, delimiter=',', quotechar='|') next(readers, None) for row in readers: rows.append(row) return rows
實如今百度搜索輸入框輸入搜索關鍵字分別是 selenium,appium,那麼實現的測試模塊 baiduTest.py 的源碼爲:
#coding:utf-8 from selenium import webdriver from ddt import ddt,data,unpack import location import time import unittest, sys neload(sys) sys.setdefaultencoding('utf-8') @ddt class BaiduTest(unittest.TestCase): def setUp(self): self.driver=webdriver.Firefox()self.driver.maximize_window() self.driver.implicitly_wait(30) self.driver.get('http://www.baidu.com/') @data(*location.getCsv("d:\\xxx.csv")) @unpack def testCase_01(self,actual,expect): '''ddt模塊與csv文件結合的使用''' self.driver.find_element_by_id('kw').send_keys(actual) time.sleep(5) def tearDown(self): self.driver.quit() if '__name__' == '__main__': suite=unittest.TestLoader().loadTestsFromTestCase(BaiduTest) unittest.TextTestRunner(verbosity=2).run(suite)
咱們就實現了單獨讀取 csv 文件中的內容,或者 csv 文件和 ddt模塊結合來在自動化中使用。
通常性的,數據存儲在 excel 中,也是一種選擇,可是必須安裝對應的庫,要不 python 是沒法操做 excel 文件的,安裝的第三方庫爲爲 xlrd, 安裝命令爲:
pip install xlrd
安裝過程:
Excel 文件的後綴格式爲.xlsx,實例中 excel 的數據爲:
因此,咱們須要讀取 excel 中的數據,首先須要 import xlrd,而後才能夠讀取 excel 文件中的數據。 在 excel 文件中, cell 是單元格,sheet 是工做表,一個工做表由 N 個單元格來組成。下面來實現讀取
excel 文件中的數據,見以下的代碼:
我把讀取 excel 中的數據寫成一個函數, 先導入 xlrd 的庫,而後建立book,以及獲取 sheet 對象,依次獲取 sheet 對象中的數據,在如上的excel 數據中,若是我想獲取「請你填寫密碼」,那麼直接調用該函數,而且傳對應的參數分別爲(0,1),見執行的代碼截圖:
若是讀取 excel 一個 sheet 對象的全部數據,修改後的代碼爲:
咱們已百度登陸爲實例,來講明 excel 文件在自動化中的引用,
測試點分別爲:
一、輸入百度帳號,未輸入百度密碼,點擊登錄,驗證返回的錯誤信息;
二、輸入錯誤的百度帳號密碼,點擊登陸,驗證返回的錯誤信息;
咱們讀 excel文件的函數,登陸百度的函數寫在 location.py的模塊中,見 location.py 模塊的代碼:
#coding:utf-8 import csv, xlrd from selenium import Webdriver import time as t def getCsv(file_name): nows = [] with open(file_name,’rb') as f: readers = csv.reader(f,delimiters = ',',quotechar = '|') next(readers,None) for row in readers: rows.append(row) return rows def getExcel(nowValue, colValue, file_name = 'd:\\xxx.xlsx'): ''' :param rowValue:表格的行 :param colValue:表格的列 :panam file_name: excel 文件 :return: ''' book = xlrd.open_workbook(file_name) sheet = book.sheet_by_index(0)return sheet.cell_value(rowValue,colValue) def clickButton(driver): driver.find_element_by_xpath("xxx").click() t.sleep(2) def clickLogin(driver, username, password): name = driver.find_element_by_id('xxx') name.clear() name.send_keys(usenname) t.sleep(2) passwd=driver.find_element_by_id('xxxx') passwd.clear() passwd.send_keys(password) t.sleep(2) driver.find_element_by_id('xxx').click() t.sleep(2) #獲取返回的錯誤信息 def getText(driver): return driver.find_element_by_xpath("xxx").text
把測試代碼寫在 baiduTest.py 的模塊中,見該模塊的測試代碼:
#coding:utf-8 from selenium import webdriver import time as t import location import unittest, sys reload(sys) sys.setdefaultencoding('utf-8') class BaiduTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.maximize_window() self.driver.implicitly一wait(30) self.driver.get('http://www.xxx.com/') def testCase_01(self): ''' 驗證只輸入百度帳號密碼,點擊登陸返回的錯誤信息 :return: ''' driver = self.driver location.clickButton(driver) location.clickLogin(driver, location.getExcel(0,0), location.getExcel(l,0)) self.assentEqual(location.getText(driver, location.getExcel(l,l)) def testCase_02(self): ''' 驗證只輸入百度帳號,未輸入密碼,點擊登陸返回的錯誤信息 :return: ''' driver = self.driver location.clickButton(driver) location.clickLogin(driver, location.getExcel(0,0),location.getExcel(2,0)) self.assentEqual(location.getText(driver, location.getExcel(0,l)) def tearDown(self): self.driver.quit() if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(BaiduTest) unittest.TextTestRunner(verbosity=2).run(suite)
這樣,咱們就實現了把測試中使用到的數據,存儲在 excel 中,而後利用 xlrd 模塊來讀取 excel 中的數據,達到測試代碼與數據的分離。
詳細的介紹了 ddt 模塊的安裝以及在自動化項目中的使用,咱們再已驗證 V 客網登陸界面爲實例,來講明 ddt 模塊在自動化中的實戰,驗證點分別爲以下幾點:
驗證點一:輸入無效的用戶名和密碼,驗證返回的錯誤信息
驗證點二:輸入有效的用戶名和無效的密碼,驗證返回的錯誤信息
驗證點三:輸入無效的郵箱和無效的密碼,驗證返回的錯誤信息
咱們把讀取數據的方法,登陸以及獲取錯誤信息,編寫的 location.py的模塊中,見 location.py 的源碼: