python 和 selenium實現web UI功能自動化測試框架(米兔888)
之前分享了python和requests搭配實現的介面自動化測試框架,今天,我再來整理分析下基於python和selenium的web UI自動化測試,希望能對大家有所幫助,也是自己整理知識學習的方法,跟大家一起努力,奮鬥在自動化測試的道路上。
其實UI自動化和介面自動化框架的設計思路大同小異,主要目的還是分離業務程式碼和測試資料,達到程式碼的複用,提高測試用例的可維護性以及最最重要的減少人工勞動力。那麼就開始直接看正文吧。
設計目的:
分離業務程式碼和測試資料,提高程式碼可維護性,實現自動化,減少重複勞動,最終達到“偷懶”的目的,哈哈哈哈哈~~ 哎呦,不好意思,一不小心暴露了真相。小編是真的在一本正經的寫程式碼啦。
框架目錄結構:
case:存放具體的測試程式碼
comm:存放共通的方法
file:存放測試用例等測試過程中用到的測試資料
result:每次測試的log和測試報告的存放位置
caseList:規定執行哪些測試
config:配置靜態資料
readConfig:讀取config檔案內容
runAll:測試執行入口檔案
一起來看整個框架的搭建。
首先,要保證你的python已經安裝了selenium包,如果你是用pip來管理自己的python環境的,那麼你可以通過下面的命令來匯入selenium模組:
pip install selenium
然後,你需要到網上去下載對應瀏覽器的驅動,這裡小編使用的是chrome瀏覽器,(chrome下載地址:http://chromedriver.storage.googleapis.com/index.html)。下載完成之後呢,將下載的瀏覽器驅動放到本地的python安裝目錄下,這樣就可以直接在框架中使用了。至此,必備的條件都有了,我們就可以開工啦。
這裡呢,我們就只挑部分內容進行講解,有許多跟介面測試框架相同或相似的方法和檔案,就不一一進行二次說明了,第一次看的盆友們,有不明白的地方可以看這篇文章,進行補充學習
開啟瀏覽器:
from selenium import webdriver
classDriver:
def__init__(self):
self.browser = webdriver.Chrome()
defopen_browser(self):
"""
Do something for browser
:return: browser
"""
# 視窗最大化
self.browser.maximize_window()
# 開啟地址連結
url = 'http://www.baidu.com'
self.browser.get(url)
return self.browser
defclose_browser(self):
"""
quit browser
:return:
"""
self.browser.quit()
從上面的程式碼可以看出,我們進行了開啟/關閉瀏覽器的方法定義,只有簡單的幾行程式碼,當然了,這裡為了方便大家觀看,我把url地址直接寫了出來,在實際操作時,我們可以將其抽離出來,根據自己的需要,傳入不同的url地址。這就留著讓大家去自己實現吧。
一個簡單的搜尋栗子:
from time import sleep
from selenium import webdriver
import unittest
classLogin(unittest.TestCase):
defsetUp(self):
self.driver = webdriver.Chrome()
# 視窗最大化
self.driver.maximize_window()
self.msg = '海賊王'
self.url = 'http://www.baidu.com'
deftestSearch(self):
"""
test body
:return:
"""
# open browser
self.driver.get(self.url)
sleep(3)
# click search input
self.driver.find_element_by_id('kw').click()
sleep(1)
# input value
self.driver.find_element_by_id('kw').send_keys(self.msg)
sleep(1)
self.driver.find_element_by_id('su').click()
sleep(1)
deftearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
在上面的程式碼裡,我們在百度裡搜尋了小編最愛的動漫,嘻嘻,是不是很開心啊,就這樣邊學邊玩耍,感覺測試也是美美的。
selenium可以通過很多種方式來定位元素。這個讀者可以自行學習。
大家看到了,這就是UI測試的雛形,有了這個雛形,我們就可以對它進行擴充套件,擴充套件,最後搭出框架來。
新增log日誌:
在上面的基礎上,我們可以新增執行時輸出的log日誌。所以開始寫log檔案,並將它放在comm資料夾下,作為共同方法來用。這部分內容在介面測試框架那裡已經介紹過了,所以請還不清楚的朋友們移步此處:https://my.oschina.net/u/3041656/blog/820023
抽離出瀏覽器的相關操作:
我們可以將對瀏覽器的操作剝離出來,單獨放到一個檔案中,這樣既清晰,又避免了重複的程式碼操作。而且維護起來也比較方便。
from selenium import webdriver
from comm.Log import MyLog as Log
import readConfig
import threading
localReadConfig = readConfig.ReadConfig()
classDriver:
def__init__(self):
self.log = Log.get_log()
self.logger = self.log.get_logger()
self.browser = webdriver.Chrome()
defopen_browser(self, name1, name2):
"""
Do something for browser
:return: browser
"""
self.logger.info("Open browser")
# 視窗最大化
self.browser.maximize_window()
# 開啟地址連結
url = localReadConfig.get_webServer(name1, name2)
self.browser.get(url)
return self.browser
defclose_browser(self):
"""
quit browser
:return:
"""
self.browser.quit()
self.logger.info("Quit browser")
defget_driver(self):
"""
get web driver
:return:
"""
return self.browser
classMyDriver:
driver = None
mutex = threading.Lock()
def__init__(self):
pass
@staticmethod
defget_browser():
if MyDriver.driver is None:
MyDriver.mutex.acquire()
MyDriver.driver = Driver()
MyDriver.mutex.release()
return MyDriver.driver
if __name__ == "__main__":
driver = MyDriver.browser()
browser = driver.open_browser()
以上便是小編剝離出來的部分,並且將它放到了單獨的執行緒中。
有木有覺得眼熟呢?其實就跟log的原理是一樣的啦。這就是“舉一反三”哦,套路就是那個套路,就看你怎麼用了。
關於Element的那些事兒:
做過UI功能測試的朋友們應該都知道,元素是我們測試最基本也是最重要的東西,以為它是我們直接的操作物件,所以,處理好它們,我們就會省掉很多的麻煩,所以呢,接下來,小編將會繼續分享自己處理element的一些方法,希望能對大家有所幫助,如果哪位大神有更好的方法,請一定要告訴小編哦!小編在此先謝過了!
classElement:
def__init__(self, activity_name, element_name):
self.driver1 = Driver.get_browser()
self.driver = self.driver1.get_driver()
self.activity = activity_name
self.element = element_name
element_dict = get_el_dict(self.activity, self.element)
self.pathType = element_dict.get('pathType')
self.pathValue = element_dict.get('pathValue')
defis_exist(self):
"""
Determine element is exist
:return: TRUE OR FALSE
"""
try:
if self.pathType == 'ID':
self.driver.find_element_by_id(self.pathValue)
return True
if self.pathType == 'XPATH':
self.driver.find_elements_by_xpath(self.pathValue)
return True
if self.pathType == 'CLASSNAME':
self.driver.find_element_by_class_name(self.pathValue)
return True
if self.pathType == 'NAME':
self.driver.find_element_by_name(self.pathValue)
return True
except NoSuchElementException:
return False
defwait_element(self, wait_time):
"""
wait element appear in time
:param wait_time: wait time
:return: true or false
"""
time.sleep(wait_time)
if self.is_exist():
return True
else:
return False
defget_element(self):
"""
get element
:return: element
"""
try:
if self.pathType == 'ID':
element = self.driver.find_element_by_id(self.pathValue)
return element
if self.pathType == 'XPATH':
element = self.driver.find_elements_by_xpath(self.pathValue)
return element
if self.pathType == 'CLASSNAME':
element = self.driver.find_element_by_class_name(self.pathValue)
return element
if self.pathType == 'NAME':
element = self.driver.find_element_by_name(self.pathValue)
return element
except NoSuchElementException:
return None
defget_element_by_index(self, index):
"""
get element by index
:param index: index
:return: element
"""
try:
if self.pathType == 'ID':
element = self.driver.find_element_by_id(self.pathValue)
return element[index]
if self.pathType == 'XPATH':
element = self.driver.find_elements_by_xpath(self.pathValue)
return element[index]
if self.pathType == 'CLASSNAME':
element = self.driver.find_element_by_class_name(self.pathValue)
return element[index]
if self.pathType == 'NAME':
element = self.driver.find_element_by_name(self.pathValue)
return element[index]
except NoSuchElementException:
return None
defget_element_list(self):
"""
get element list
:return: element list
"""
try:
if self.pathType == 'ID':
element_list = self.driver.find_element_by_id(self.pathValue)
return element_list
if self.pathType == 'XPATH':
element_list = self.driver.find_elements_by_xpath(self.pathValue)
return element_list
if self.pathType == 'CLASSNAME':
element_list = self.driver.find_element_by_class_name(self.pathValue)
return element_list
if self.pathType == 'NAME':
element_list = self.driver.find_element_by_name(self.pathValue)
return element_list
except NoSuchElementException:
return None
defclick(self):
"""
click element
:return:
"""
element = self.get_element()
time.sleep(1)
element.click()
defsend_key(self, key):
"""
input key
:param key: input value
:return:
"""
element = self.get_element()
time.sleep(1)
element.clear()
element.send_keys(key)
definput_keys(self, index, key):
"""
By index send key
:param index: index
:param key: key
:return:
"""
element = self.get_element_by_index(index)
time.sleep(1)
element.clear()
element.send_keys(key)
defget_text_value(self):
"""
get attribute
:return:
"""
element = self.get_element()
value = element.get_attribute('text')
return str(value)
這是小編寫的,目前能用到的關於element的方法了,累覺不愛啊~
但是,生活還要繼續,工作還未完成。所以,請讓我講完剩下的程式碼吧!!!
那些讓人費神的測試資料檔案:
每一個好的測試,都離不開一份好的測試用例資料,那麼,這麼多的資料,我們要怎樣進行管理才能既不亂又方便以後對資料進行更改維護呢?下面,小編就要告訴朋友們一個重磅訊息,敲黑板!!!
其實,小編也不知道有什麼好辦法,小編就是使用excel檔案來對測試用例進行統一管理的。請看下面:
形式就是這麼個形式,內容就隨便你們怎麼修改了。畢竟我也只能幫你們到這裡了。至於對excel檔案內容的讀取,在介面測試那篇博文中也有詳細介紹哦。不明白的同學請移步:https://my.oschina.net/u/3041656/blog/820023
其實,出來測試用例,還有一個數量龐大的資料群體,快猜猜它們是誰???
噹噹噹,答案就是:元素定位的資料,包括:id,name,classname,xpath等等,這些資料可是我們在測試過程中找到頁面元素的不二法門哦。。。所以各位朋友一定要注意啦,一定要處理好它們。
請看下面:
愚蠢的小編就用xml檔案來管理啦。
是不是又有人想問怎麼讀取xml檔案了?嘿嘿。。。我不會告訴你的,因為我在前面的博文裡已經講過啦!講過啦!過啦!啦!!
至此呢,今天的內容也結束了,希望對大家有所啟發和幫助,雖然講的有些凌亂,不過只要弄懂了這些劃分和實現方法,我相信,你也一定可以寫出自己滿意的UI自動化測試框架。所以,我們一起加油吧。
本文為原創文章,轉載請註明原文地址,謝謝大家的支援。希望大家一起努力成長。
如果覺得本文的文章寫得很好,打個賞,多少都行~~~
如果覺得本文的文章寫得很好,打個賞,多少都行~~~