Selenium自動(dòng)化測(cè)試-unittest單元測(cè)試框架使用
一、unittest
unittest是一個(gè)單元測(cè)試框架,是Python編程的單元測(cè)試框架。有時(shí)候,也做叫做“PyUnit”,是Junit的Python語言版本。這里了解下,Junit是Java語言的單元測(cè)試框架,Java還有一個(gè)很好用的單元測(cè)試框架叫TestNG,本系列只學(xué)習(xí)Python,所以只需要unittest是Python里的一個(gè)單元測(cè)試框架就可以了。
unittest支持測(cè)試自動(dòng)化,共享測(cè)試用例中的初始化和關(guān)閉退出代碼,在unittest中最小單元是test,也就是一個(gè)測(cè)試用例。要了解unittest單元測(cè)試框架,先來了解以下幾個(gè)重要的概念。
1. 測(cè)試固件(test fixture)
一個(gè)測(cè)試固件包括兩部分,執(zhí)行測(cè)試代碼之前的準(zhǔn)備部分和測(cè)試結(jié)束之后的清掃代碼。這兩部分一般用函數(shù)setUp()和tearDown()表示。這里舉例以下,例如要測(cè)試百度搜索selenium這個(gè)場(chǎng)景,我們的測(cè)試固件可以這樣寫,setUp()里寫打開瀏覽器,瀏覽器最大化,和打開百度首頁等腳本代碼;在tearDown()里寫結(jié)束搜索后,退出并關(guān)閉瀏覽器的代碼。
2. 測(cè)試用例(test case)
unittest中管理的最小單元是測(cè)試用例,一個(gè)測(cè)試用例,包括測(cè)試固件,和具體測(cè)試業(yè)務(wù)的函數(shù)或者方法。一個(gè)測(cè)試用例中,測(cè)試固件可以不寫,但是至少有一個(gè)已test開頭的函數(shù)。unittest會(huì)自動(dòng)化識(shí)別test開頭的函數(shù)是測(cè)試代碼,如果你寫的函數(shù)不是test開頭,unittest是不會(huì)執(zhí)行這個(gè)函數(shù)里面的腳本的,這個(gè)千萬要記住,所有的測(cè)試函數(shù)都要test開頭,記住是小寫的哦。
3. 測(cè)試套件 (test suite)
很簡(jiǎn)單,就是很多測(cè)試用例的集合,叫測(cè)試套件,一個(gè)測(cè)試套件可以隨意管理多個(gè)測(cè)試用例。如果測(cè)試用例比作單個(gè)學(xué)生,測(cè)試套件就是好像是班級(jí)的概念。
4. 測(cè)試執(zhí)行器 (test runner)
test runner是一個(gè)用來執(zhí)行加載測(cè)試用例,并執(zhí)行用例,且提供測(cè)試輸出的一個(gè)組建。test runner可以加載test case或者test suite進(jìn)行執(zhí)行測(cè)試任務(wù)。
我們舉例來,練習(xí)一下test fixture和test case的使用,學(xué)習(xí)unittest的簡(jiǎn)單用法:
1.新建一個(gè)testbaidu.py的文件
2.導(dǎo)入unittest模塊
3.當(dāng)前測(cè)試類繼承unittest.TestCase,相當(dāng)于當(dāng)前利用unittest創(chuàng)建了一個(gè)test case,這個(gè)test case是能夠被unittest直接識(shí)別。
4.寫setUp(),主要是打開瀏覽器和打開站點(diǎn)
5.寫一個(gè)test_search()用例寫搜索的代碼
6.寫tearDown(),主要是瀏覽器退出操作
相關(guān)腳本代碼如下:
# coding=utf-8
import time
import unittest
from selenium import webdriver
class BaiduSearch(unittest.TestCase):
def setUp(self):
"""
測(cè)試固件的setUp()的代碼,主要是測(cè)試的前提準(zhǔn)備工作
:return:
"""
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(8)
self.driver.get("https://www.baidu.com")
def tearDown(self):
"""
測(cè)試結(jié)束后的操作,這里基本上都是關(guān)閉瀏覽器
:return:
"""
self.driver.quit()
def test_baidu_search(self):
"""
這里一定要test開頭,把測(cè)試邏輯代碼封裝到一個(gè)test開頭的方法里。
:return:
"""
self.driver.find_element_by_id('kw').send_keys('selenium')
time.sleep(1)
self.driver.find_element_by_id('su').click()
time.sleep(1)
try:
assert 'selenium' in self.driver.title
print ('Test Pass.')
except Exception as e:
print ('Test Fail.', format(e))
if __name__ == '__main__':
unittest.main()
二、
- 基類base_page.py的具體實(shí)現(xiàn)代碼,這里就封裝了幾個(gè)常用方法。
- baidu_homepage.py頁面對(duì)象中,百度主頁的元素定位和簡(jiǎn)單的操作函數(shù),頁面類主要是元素定位和頁面操作寫成函數(shù),供測(cè)試類調(diào)用。
- 測(cè)試類的寫法舉例:
import time
import unittest
from selenium_package.browser_engine import BrowserEngine
from pageobject.baidu_homepage import HomePage
class BaiduSearch2(unittest.TestCase):
def setUp(self):
"""
測(cè)試固件的setUp()的代碼,主要是測(cè)試的前提準(zhǔn)備工作
:return:
"""
browse = BrowserEngine(self)
self.driver = browse.open_browser(self)
def tearDown(self):
"""
測(cè)試結(jié)束后的操作,這里基本上都是關(guān)閉瀏覽器
:return:
"""
self.driver.quit()
def test_baidu_search2(self):
"""
這里一定要test開頭,把測(cè)試邏輯代碼封裝到一個(gè)test開頭的方法里。
:return:
"""
homepage = HomePage(self.driver)
# 上面這行代碼要注意,意思是,到一個(gè)頁面,第一件事情是初始化這個(gè)頁面的一個(gè)頁面對(duì)象實(shí)例。
# 注意,一定要帶self.driver,不然會(huì)報(bào)錯(cuò),這個(gè)self.driver,可以這樣理解:
# 在當(dāng)前測(cè)試類里面,self.driver是來自瀏覽器引擎類中方法得到的,
# 在初始化一個(gè)頁面對(duì)象的時(shí)候,也把這個(gè)來自瀏覽器引擎類的driver給賦值給當(dāng)前的頁面對(duì)象,
# 這樣,才能執(zhí)行頁面對(duì)象或者基類里面的相關(guān)driver方法。
# 寫多了selenium的自動(dòng)化腳本,你會(huì)明白,最重要的是保持前后driver的唯一性。
homepage.type_search('selenium') # 調(diào)用頁面對(duì)象中的方法
homepage.send_submit_btn() # 調(diào)用頁面對(duì)象類中的點(diǎn)擊搜索按鈕方法
time.sleep(2)
homepage.get_windows_img() # 調(diào)用基類截圖方法
try:
assert 'selenium' in homepage.get_page_title() # 調(diào)用頁面對(duì)象繼承基類中的獲取頁面標(biāo)題方法
print('test pass')
except Exception as e:
print('Test Fail.', format(e))
def test_search2(self):
homepage = HomePage(self.driver)
homepage.type_search('python') # 調(diào)用頁面對(duì)象中的方法
homepage.send_submit_btn() # 調(diào)用頁面對(duì)象類中的點(diǎn)擊搜索按鈕方法
time.sleep(2)
homepage.get_windows_img() # 調(diào)用基類截圖方法
if __name__ == '__main__':
unittest.main()
問題發(fā)現(xiàn)了沒,我們的瀏覽器啟動(dòng)和關(guān)閉了兩次,是不是這個(gè)問題?原來,沒執(zhí)行一次test開頭的函數(shù),都要執(zhí)行一次測(cè)試固件,也就是說執(zhí)行setUp()和()一次,如果有N個(gè)test開頭的函數(shù),測(cè)試固件就執(zhí)行N次,我們到底有沒有,只需要執(zhí)行一次測(cè)試固件,支持執(zhí)行多次測(cè)試函數(shù)。
我們測(cè)試中,肯定需要,打開一個(gè)頁面,然后測(cè)試這個(gè)頁面的多個(gè)用例,才關(guān)閉這個(gè)頁面,去測(cè)試其他頁面,在unittest是有相關(guān)測(cè)試固件方法去支持這種行為。請(qǐng)看下面調(diào)整,自己對(duì)比下,能不能找出不同。
class BaiduSearch(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""
測(cè)試固件的setUp()的代碼,主要是測(cè)試的前提準(zhǔn)備工作
:return:
"""
browse = BrowserEngine(cls)
cls.driver = browse.open_browser(cls)
@classmethod
def tearDownClass(cls):
"""
測(cè)試結(jié)束后的操作,這里基本上都是關(guān)閉瀏覽器
:return:
"""
cls.driver.quit()
補(bǔ)充:
# @classmethod和 @ setUpclass(cls) 接口測(cè)試 token處理用法詳解: