軟件測(cè)試教程 自動(dòng)化測(cè)試selenium篇(三)
之前講解了selenium的腳本錄制和api。在進(jìn)行腳本錄制導(dǎo)出的腳本中归露,我們發(fā)現(xiàn)其中多了很多代碼哼丈,這些代碼正是unittest測(cè)試框架。
class chandao(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://127.0.0.1/"
self.verificationErrors = []
self.accept_next_alert = True
現(xiàn)在我們編寫(xiě)了單獨(dú)的腳本训枢,但是我們還缺少以下的部分道伟,只有當(dāng)有了以下部分晋修,才能將自動(dòng)化測(cè)試組織起來(lái)并持續(xù)進(jìn)行玄捕。
批量執(zhí)行
參數(shù)化
斷言
測(cè)試報(bào)告
本課程將圍繞unittest來(lái)介紹測(cè)試框架车胡。
unittest框架解析
批量執(zhí)行腳本
unittest斷言
HTML報(bào)告生成
異常捕捉與錯(cuò)誤截圖
數(shù)據(jù)驅(qū)動(dòng)
unittest框架解析
unittest 是python 的單元測(cè)試框架, 在python 的官方文檔中十酣,對(duì)unittest有詳細(xì)的介紹涩拙,想更深一步研究的同學(xué)可以到https://www.python.org/doc/ 去了解际长。
unittest 單元測(cè)試提供了創(chuàng)建測(cè)試用例,測(cè)試套件以及批量執(zhí)行的方案兴泥, unittest 在安裝pyhton 以后就直接自帶了工育,直接import unittest 就可以使用。
作為單元測(cè)試的框架搓彻, unittest 也是可以對(duì)程序最小模塊的一種敏捷化的測(cè)試如绸。在自動(dòng)化測(cè)試中,我們雖然不需要做白盒測(cè)試旭贬,但是必須需要知道所使用語(yǔ)言的單元測(cè)試框架怔接。利用單元測(cè)試框架,創(chuàng)建一個(gè)類稀轨,該類繼承unittest 的TestCase扼脐,這樣可以把每個(gè)case看成是一個(gè)最小的單元, 由測(cè)試容器組織起來(lái)奋刽,到時(shí)候直接執(zhí)行瓦侮,同時(shí)引入測(cè)試報(bào)告。
unittest 各組件的關(guān)系為:
- test fixture:初始化和清理測(cè)試環(huán)境佣谐,比如創(chuàng)建臨時(shí)的數(shù)據(jù)庫(kù)肚吏,文件和目錄等,其中 setUp() 和 setDown() 是最常用的方法
- test case:?jiǎn)卧獪y(cè)試用例台谍,TestCase 是編寫(xiě)單元測(cè)試用例最常用的類
- test suite:?jiǎn)卧獪y(cè)試用例的集合须喂,TestSuite 是最常用的類
- test runner:執(zhí)行單元測(cè)試
- test report:生成測(cè)試報(bào)告
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Baidu1(unittest.TestCase):
#test fixture吁断,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#測(cè)試用例趁蕊,必須以test開(kāi)頭
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"測(cè)試")
driver.find_element_by_id("su").click()
driver.find_element_by_id("su").click()
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
self.assertEqual(u"hao123_上網(wǎng)從這里開(kāi)始", driver.title)
#判斷element是否存在,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在仔役,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert掷伙,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
'''
可以增加verbosity參數(shù)又兵,例如unittest.main(verbosity=2)
在主函數(shù)中任柜,直接調(diào)用main() ,在main中加入verbosity=2 沛厨,這樣測(cè)試的結(jié)果就會(huì)顯示的更加詳細(xì)宙地。
這里的verbosity 是一個(gè)選項(xiàng), 表示測(cè)試結(jié)果的信息復(fù)雜度,有三個(gè)值:
0 ( 靜默模式): 你只能獲得總的測(cè)試用例數(shù)和總的結(jié)果比如總共100個(gè)失敗,20 成功80
1 ( 默認(rèn)模式): 非常類似靜默模式只是在每個(gè)成功的用例前面有個(gè)“ . ” 每個(gè)失敗的用例前面有個(gè)“F”
2 ( 詳細(xì)模式): 測(cè)試結(jié)果會(huì)顯示每個(gè)測(cè)試用例的所有相關(guān)的信息
'''
批量執(zhí)行腳本
構(gòu)建測(cè)試套件
完整的單元測(cè)試很少只執(zhí)行一個(gè)測(cè)試用例逆皮,開(kāi)發(fā)人員通常都需要編寫(xiě)多個(gè)測(cè)試用例才能對(duì)某一軟件功能進(jìn)行比較完整的測(cè)試宅粥,這些相關(guān)的測(cè)試用例稱為一個(gè)測(cè)試用例集,在unittest中是用TestSuite 類來(lái)表示的电谣。
假設(shè)我們已經(jīng)編寫(xiě)了testbaidu1.py秽梅,testbaidu2.py兩個(gè)文件抹蚀,那么我們?cè)趺赐瑫r(shí)執(zhí)行這兩個(gè)文件呢?
testbaidu1.py
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Baidu1(unittest.TestCase):
#test fixture企垦,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#測(cè)試用例环壤,必須以test開(kāi)頭
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"測(cè)試")
driver.find_element_by_id("su").click()
driver.find_element_by_id("su").click()
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
self.assertEqual(u"hao123_上網(wǎng)從這里開(kāi)始", driver.title)
#判斷element是否存在,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在钞诡,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert郑现,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
testbaidu2.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Baidu2(unittest.TestCase):
#test fixture荧降,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#測(cè)試用例懂酱,必須以test開(kāi)頭
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"selenium")
driver.find_element_by_id("su").click()
driver.find_element_by_id("su").click()
#判斷element是否存在,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在誊抛,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert列牺,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
addTest() 的應(yīng)用
當(dāng)有多個(gè)或者幾百測(cè)試用例的時(shí)候拗窃, 這樣就需要一個(gè)測(cè)試容器( 測(cè)試套件) 瞎领,把測(cè)試用例放在該容器中進(jìn)行執(zhí)行, unittest 模塊中提供了TestSuite 類來(lái)生成測(cè)試套件随夸,使用該類的構(gòu)造函數(shù)可以生成一個(gè)測(cè)試套件的實(shí)例九默,該類提供了addTest來(lái)把每個(gè)測(cè)試用例加入到測(cè)試套件中。
將testbaidu1.py宾毒、testbaidu2.py驼修、runall.py放在同一個(gè)目錄testcase中
runall.py
# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
#導(dǎo)入testbaidu1,testbaidu2
import testbaidu1
import testbaidu2
#手工添加案例到套件诈铛,
def createsuite():
suite = unittest.TestSuite()
#將測(cè)試用例加入到測(cè)試容器(套件)中
suite.addTest(testbaidu1.Baidu1("test_baidusearch"))
suite.addTest(testbaidu1.Baidu1("test_hao"))
suite.addTest(testbaidu2.Baidu2("test_baidusearch"))
return suite
if __name__=="__main__":
suite=createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
上述做法有兩個(gè)不方面的地方乙各,阻礙腳本的快速執(zhí)行,必須每次修改runall.py:
1)需要導(dǎo)入所有的py文件幢竹,比如import testbaidu1耳峦,每新增一個(gè)需要導(dǎo)入一個(gè)
2)addTest需要增加所有的testcase,如果一個(gè)py文件中有10個(gè)case焕毫,就需要增加10次
makeSuite()和TestLoader()的應(yīng)用
在unittest 框架中提供了makeSuite() 的方法蹲坷,makeSuite可以實(shí)現(xiàn)把測(cè)試用例類內(nèi)所有的測(cè)試case組成的測(cè)試套件TestSuite ,unittest 調(diào)用makeSuite的時(shí)候邑飒,只需要把測(cè)試類名稱傳入即可循签。
TestLoader 用于創(chuàng)建類和模塊的測(cè)試套件,一般的情況下疙咸,使TestLoader().loadTestsFromTestCase(TestClass) 來(lái)加載測(cè)試類县匠。
runall.py
# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
import testbaidu1
import testbaidu2
#手工添加案例到套件,
def createsuite():
suite = unittest.TestSuite()
#將測(cè)試用例加入到測(cè)試容器(套件)中
suite.addTest(unittest.makeSuite(testbaidu1.Baidu1))
suite.addTest(unittest.makeSuite(testbaidu2.Baidu2))
return suite
'''
suite1 = unittest.TestLoader().loadTestsFromTestCase(testbaidu1.Baidu1)
suite2 = unittest.TestLoader().loadTestsFromTestCase(testbaidu2.Baidu2)
suite = unittest.TestSuite([suite1, suite2])
return suite
'''
if __name__=="__main__":
suite=createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
經(jīng)過(guò)makeSuite()和TestLoader()的引入,我們不用一個(gè)py文件測(cè)試類聚唐,只需要導(dǎo)入一次即可丐重。
那么能不能測(cè)試類也不用每次添加指定呢?
discover()的應(yīng)用
discover 是通過(guò)遞歸的方式到其子目錄中從指定的目錄開(kāi)始杆查, 找到所有測(cè)試模塊并返回一個(gè)包含它們對(duì)象的TestSuite 扮惦,然后進(jìn)行加載與模式匹配唯一的測(cè)試文件,discover 參數(shù)分別為discover(dir,pattern,top_level_dir=None)
runall.py
# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
#手工添加案例到套件亲桦,
def createsuite():
discover=unittest.defaultTestLoader.discover('../testcase',pattern='test*.py',top_level_dir=None)
print discover
return discover
if __name__=="__main__":
suite=createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
用例的執(zhí)行順序
unittest 框架默認(rèn)加載測(cè)試用例的順序是根據(jù)ASCII 碼的順序崖蜜,數(shù)字與字母的順序?yàn)椋?09,AZ,a~z 。
所以客峭, TestAdd 類會(huì)優(yōu)先于TestBdd 類被發(fā)現(xiàn)豫领, test_aaa() 方法會(huì)優(yōu)先于test_ccc() 被執(zhí)行。對(duì)于測(cè)試目錄與測(cè)試文件來(lái)說(shuō)舔琅, unittest 框架同樣是按照這個(gè)規(guī)則來(lái)加載測(cè)試用例等恐。
addTest()方法按照增加順序來(lái)執(zhí)行。
忽略用例執(zhí)行
@unittest.skip(u'The function was canceled, neglects to perform thecase')
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Baidu1(unittest.TestCase):
#test fixture备蚓,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
@unittest.skip("skipping")
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"測(cè)試")
driver.find_element_by_id("su").click()
driver.find_element_by_id("su").click()
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
self.assertEqual(u"hao123_上網(wǎng)從這里開(kāi)始", driver.title)
#判斷element是否存在课蔬,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert郊尝,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture二跋,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
unittest斷言
自動(dòng)化的測(cè)試中, 對(duì)于每個(gè)單獨(dú)的case來(lái)說(shuō)流昏,一個(gè)case的執(zhí)行結(jié)果中扎即, 必然會(huì)有期望結(jié)果與實(shí)際結(jié)果, 來(lái)判斷該case是通過(guò)還是失敗况凉, 在unittest 的庫(kù)中提供了大量的實(shí)用方法來(lái)檢查預(yù)期值與實(shí)際值谚鄙, 來(lái)驗(yàn)證case的結(jié)果, 一般來(lái)說(shuō)茎刚, 檢查條件大體分為等價(jià)性襟锐, 邏輯比較以及其他撤逢, 如果給定的斷言通過(guò)膛锭, 測(cè)試會(huì)繼續(xù)執(zhí)行到下一行的代碼, 如果斷言失敗蚊荣, 對(duì)應(yīng)的case測(cè)試會(huì)立即停止或者生成錯(cuò)誤信息( 一般打印錯(cuò)誤信息即可) 初狰,但是不要影響其他的case執(zhí)行。
unittest 的單元測(cè)試庫(kù)提供了標(biāo)準(zhǔn)的xUnit 斷言方法互例。下面是一些常用的斷言
序號(hào) | 斷言方法 | 斷言描述 |
---|---|---|
1 | assertEqual(arg1, arg2, msg=None) | 驗(yàn)證arg1=arg2奢入,不等則fail |
2 | assertNotEqual(arg1, arg2, msg=None) | 驗(yàn)證arg1 != arg2, 相等則fail |
3 | assertTrue(expr, msg=None) | 驗(yàn)證expr是true,如果為false媳叨,則fail |
4 | assertFalse(expr,msg=None) | 驗(yàn)證expr是false腥光,如果為true关顷,則fail |
5 | assertIs(arg1, arg2, msg=None) | 驗(yàn)證arg1、arg2是同一個(gè)對(duì)象武福,不是則fail |
6 | assertIsNot(arg1, arg2, msg=None) | 驗(yàn)證arg1议双、arg2不是同一個(gè)對(duì)象,是則fail |
7 | assertIsNone(expr, msg=None) | 驗(yàn)證expr是None捉片,不是則fail |
8 | assertIsNotNone(expr, msg=None) | 驗(yàn)證expr不是None平痰,是則fail |
9 | assertIn(arg1, arg2, msg=None) | 驗(yàn)證arg1是arg2的子串,不是則fail |
10 | assertNotIn(arg1, arg2, msg=None) | 驗(yàn)證arg1不是arg2的子串伍纫,是則fail |
11 | assertIsInstance(obj, cls, msg=None) | 驗(yàn)證obj是cls的實(shí)例宗雇,不是則fail |
12 | assertNotIsInstance(obj, cls, msg=None) | 驗(yàn)證obj不是cls的實(shí)例,是則fail |
舉例:
self.assertEqual("admin", driver.find_element_by_link_text("admin").text)
可以通過(guò)IDE來(lái)添加斷言:
HTML報(bào)告生成
腳本執(zhí)行完畢之后莹规,還需要看到HTML報(bào)告赔蒲,下面我們就通過(guò)HTMLTestRunner.py 來(lái)生成測(cè)試報(bào)告。HTMLTestRunner支持python2.7良漱。python3可以參見(jiàn)http://blog.51cto.com/hzqldjb/1590802來(lái)進(jìn)行修改嘹履。
HTMLTestRunner.py 文件,下載地址:
http://tungwaiyip.info/software/HTMLTestRunner.html
下載后將其放在testcase目錄中去或者放入...\Python27\Lib 目錄下(windows)债热。
修改runall.py
# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
import HTMLTestRunner
#手工添加案例到套件砾嫉,
def createsuite():
discover=unittest.defaultTestLoader.discover('./testcase',pattern='test*.py',top_level_dir=None)
print discover
return discover
if __name__=="__main__":
curpath=sys.path[0]
#取當(dāng)前時(shí)間
now=time.strftime("%Y-%m-%d-%H %M %S",time.localtime(time.time()))
if not os.path.exists(curpath+'/resultreport'):
os.makedirs(curpath+'/resultreport')
filename=curpath+'/resultreport/'+now+'resultreport.html'
with open(filename,'wb') as fp:
#出html報(bào)告
runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title=u'測(cè)試報(bào)告',description=u'用例執(zhí)行情況',verbosity=2)
suite=createsuite()
runner.run(suite)
異常捕捉與錯(cuò)誤截圖
用例不可能每一次運(yùn)行都成功,肯定運(yùn)行時(shí)候有不成功的時(shí)候窒篱。如果可以捕捉到錯(cuò)誤焕刮,并且把錯(cuò)誤截圖保存,這將是一個(gè)非常棒的功能墙杯,也會(huì)給我們錯(cuò)誤定位帶來(lái)方便配并。
例如編寫(xiě)一個(gè)函數(shù),關(guān)鍵語(yǔ)句為driver.get_screenshot_as_file:
def savescreenshot(self,driver,file_name):
if not os.path.exists('./image'):
os.makedirs('./image')
now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
#截圖保存
driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
time.sleep(1)
一個(gè)引用的例子:
testscreenshot.py
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
import os
class Baidu1(unittest.TestCase):
#test fixture高镐,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#測(cè)試用例溉旋,必須以test開(kāi)頭
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
time.sleep(2)
try:
self.assertEqual(u'hao_上網(wǎng)從這里開(kāi)始', driver.title)
except:
self.savescreenshot(driver,'hao.png')
#判斷element是否存在,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在嫉髓,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert观腊,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
def savescreenshot(self,driver,file_name):
if not os.path.exists('./image'):
os.makedirs('./image')
now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
#截圖保存
driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
time.sleep(1)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
'''
可以增加verbosity參數(shù)算行,例如unittest.main(verbosity=2)
在主函數(shù)中梧油,直接調(diào)用main() ,在main中加入verbosity=2 州邢,這樣測(cè)試的結(jié)果就會(huì)顯示的更加詳細(xì)儡陨。
這里的verbosity 是一個(gè)選項(xiàng), 表示測(cè)試結(jié)果的信息復(fù)雜度,有三個(gè)值:
0 ( 靜默模式): 你只能獲得總的測(cè)試用例數(shù)和總的結(jié)果比如總共100個(gè)失敗,20 成功80
1 ( 默認(rèn)模式): 非常類似靜默模式只是在每個(gè)成功的用例前面有個(gè)“ . ” 每個(gè)失敗的用例前面有個(gè)“F”
2 ( 詳細(xì)模式): 測(cè)試結(jié)果會(huì)顯示每個(gè)測(cè)試用例的所有相關(guān)的信息
'''
數(shù)據(jù)驅(qū)動(dòng)
之前我們的case都是數(shù)據(jù)和代碼在一起編寫(xiě)∑澹考慮如下場(chǎng)景:
需要多次執(zhí)行一個(gè)案例嫌褪,比如baidu搜索,分別輸入中文胚股、英文渔扎、數(shù)字等進(jìn)行搜索,這時(shí)候需要編寫(xiě)3個(gè)案例嗎信轿?有沒(méi)有版本一次運(yùn)行晃痴?
python 的unittest 沒(méi)有自帶數(shù)據(jù)驅(qū)動(dòng)功能。所以如果使用unittest财忽,同時(shí)又想使用數(shù)據(jù)驅(qū)動(dòng)倘核,那么就可以使用DDT來(lái)完成。
ddt的安裝:
pip install ddt
ddt使用方法:
參考文檔:http://ddt.readthedocs.io/en/latest/
dd.ddt:
裝飾類即彪,也就是繼承自TestCase的類紧唱。
ddt.data:
裝飾測(cè)試方法。參數(shù)是一系列的值隶校。
ddt.file_data:
裝飾測(cè)試方法漏益。參數(shù)是文件名。文件可以是json 或者 yaml類型深胳。
注意绰疤,如果文件以”.yml”或者”.yaml”結(jié)尾,ddt會(huì)作為yaml類型處理舞终,其他所有文件都會(huì)作為json文件處理轻庆。
如果文件中是列表,每個(gè)列表的值會(huì)作為測(cè)試用例參數(shù)敛劝,同時(shí)作為測(cè)試用例方法名后綴顯示余爆。
如果文件中是字典,字典的key會(huì)作為測(cè)試用例方法的后綴顯示夸盟,字典的值會(huì)作為測(cè)試用例參數(shù)蛾方。
ddt.unpack:
傳遞的是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)時(shí)使用。比如使用元組或者列表上陕,添加unpack之后桩砰,ddt會(huì)自動(dòng)把元組或者列表對(duì)應(yīng)到多個(gè)參數(shù)上。字典也可以這樣處理唆垃。
下面看一個(gè)樣例:
test_data_list.json:
[
"Hello",
"Goodbye"
]
Testddt.py:
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
import os,sys,csv
from ddt import ddt, data, unpack ,file_data
def getCsv(file_name):
rows=[]
path=sys.path[0].replace('\\test_case','')
print path
with open(path+'/data/'+file_name,'rb') as f:
readers=csv.reader(f,delimiter=',',quotechar='|')
next(readers,None)
for row in readers:
temprows=[]
for i in row:
temprows.append(i.decode('gbk'))
rows.append(temprows)
return rows
#引入ddt
@ddt
class Testddt(unittest.TestCase):
#test fixture五芝,初始化環(huán)境
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#測(cè)試用例,必須以test開(kāi)頭
#增加ddt數(shù)據(jù)
#@data('selenium',u'測(cè)試中文','9999999999')
@data(*getCsv('test_baidu_data.csv'))
#使用file_data需要在cmd窗口下運(yùn)行辕万,否則找不到文件
#@file_data('test_data_list.json')
@unpack
def test_hao(self,value,expected_value):
#def test_hao(self,value):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
time.sleep(2)
self.assertEqual(expected_value, driver.title)
#判斷element是否存在,可刪除
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
#判斷alert是否存在,可刪除
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
#關(guān)閉alert渐尿,可刪除
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
#test fixture醉途,清除環(huán)境
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
def savescreenshot(self,driver,file_name):
if not os.path.exists('./image'):
os.makedirs('./image')
now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
#截圖保存
driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
time.sleep(1)
if __name__ == "__main__":
#執(zhí)行用例
unittest.main()
'''
可以增加verbosity參數(shù),例如unittest.main(verbosity=2)
在主函數(shù)中砖茸,直接調(diào)用main() 隘擎,在main中加入verbosity=2 ,這樣測(cè)試的結(jié)果就會(huì)顯示的更加詳細(xì)凉夯。
這里的verbosity 是一個(gè)選項(xiàng), 表示測(cè)試結(jié)果的信息復(fù)雜度货葬,有三個(gè)值:
0 ( 靜默模式): 你只能獲得總的測(cè)試用例數(shù)和總的結(jié)果比如總共100個(gè)失敗,20 成功80
1 ( 默認(rèn)模式): 非常類似靜默模式只是在每個(gè)成功的用例前面有個(gè)“ . ” 每個(gè)失敗的用例前面有個(gè)“F”
2 ( 詳細(xì)模式): 測(cè)試結(jié)果會(huì)顯示每個(gè)測(cè)試用例的所有相關(guān)的信息
'''