以前分享了python和requests搭配實現的接口自動化測試框架,今天,我再來整理分析下基於python和selenium的web UI自動化測試,但願能對你們有所幫助,也是本身整理知識學習的方法,跟你們一塊兒努力,奮鬥在自動化測試的道路上。html
其實UI自動化和接口自動化框架的設計思路大同小異,主要目的仍是分離業務代碼和測試數據,達到代碼的複用,提升測試用例的可維護性以及最最重要的減小人工勞動力。那麼就開始直接看正文吧。python
設計目的:web
分離業務代碼和測試數據,提升代碼可維護性,實現自動化,減小重複勞動,最終達到「偷懶」的目的,哈哈哈哈哈~~ 哎呦,很差意思,一不當心暴露了真相。小編是真的在一本正經的寫代碼啦。chrome
框架目錄結構:api
case:存放具體的測試代碼瀏覽器
comm:存放共通的方法app
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安裝目錄下,這樣就能夠直接在框架中使用了。至此,必備的條件都有了,咱們就能夠開工啦。
這裏呢,咱們就只挑部份內容進行講解,有許多跟接口測試框架相同或類似的方法和文件,就不一一進行二次說明了,第一次看的盆友們,有不明白的地方能夠看這篇文章,進行補充學習http://www.javashuo.com/article/p-koqjlcfy-ku.html
打開瀏覽器:
from selenium import webdriver class Driver: def __init__(self): self.browser = webdriver.Chrome() def open_browser(self): """ Do something for browser :return: browser """ # 窗口最大化 self.browser.maximize_window() # 打開地址連接 url = 'http://www.baidu.com' self.browser.get(url) return self.browser def close_browser(self): """ quit browser :return: """ self.browser.quit()
從上面的代碼能夠看出,咱們進行了打開/關閉瀏覽器的方法定義,只有簡單的幾行代碼,固然了,這裏爲了方便你們觀看,我把url地址直接寫了出來,在實際操做時,咱們能夠將其抽離出來,根據本身的須要,傳入不一樣的url地址。這就留着讓你們去本身實現吧。
一個簡單的搜索栗子:
from time import sleep from selenium import webdriver import unittest class Login(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() # 窗口最大化 self.driver.maximize_window() self.msg = '海賊王' self.url = 'http://www.baidu.com' def testSearch(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) def tearDown(self): self.driver.close() if __name__ == "__main__": unittest.main()
在上面的代碼裏,咱們在百度裏搜索了小編最愛的動漫,嘻嘻,是否是很開心啊,就這樣邊學邊玩耍,感受測試也是美美的。
selenium能夠經過不少種方式來定位元素。這個讀者能夠自行學習。
你們看到了,這就是UI測試的雛形,有了這個雛形,咱們就能夠對它進行擴展,擴展,最後搭出框架來。
添加log日誌:
在上面的基礎上,咱們能夠添加執行時輸出的log日誌。因此開始寫log文件,並將它放在comm文件夾下,做爲共同方法來用。這部份內容在接口測試框架那裏已經介紹過了,因此請還不清楚的朋友們移步此處:http://www.javashuo.com/article/p-koqjlcfy-ku.html
抽離出瀏覽器的相關操做:
咱們能夠將對瀏覽器的操做剝離出來,單獨放到一個文件中,這樣既清晰,又避免了重複的代碼操做。並且維護起來也比較方便。
from selenium import webdriver from comm.Log import MyLog as Log import readConfig import threading localReadConfig = readConfig.ReadConfig() class Driver: def __init__(self): self.log = Log.get_log() self.logger = self.log.get_logger() self.browser = webdriver.Chrome() def open_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 def close_browser(self): """ quit browser :return: """ self.browser.quit() self.logger.info("Quit browser") def get_driver(self): """ get web driver :return: """ return self.browser class MyDriver: driver = None mutex = threading.Lock() def __init__(self): pass @staticmethod def get_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的一些方法,但願能對你們有所幫助,若是哪位大神有更好的方法,請必定要告訴小編哦!小編在此先謝過了!
class Element: 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') def is_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 def wait_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 def get_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 def get_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 def get_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 def click(self): """ click element :return: """ element = self.get_element() time.sleep(1) element.click() def send_key(self, key): """ input key :param key: input value :return: """ element = self.get_element() time.sleep(1) element.clear() element.send_keys(key) def input_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) def get_text_value(self): """ get attribute :return: """ element = self.get_element() value = element.get_attribute('text') return str(value)
這是小編寫的,目前能用到的關於element的方法了,累覺不愛啊~
可是,生活還要繼續,工做還未完成。因此,請讓我講完剩下的代碼吧!!!
那些讓人費神的測試數據文件:
每個好的測試,都離不開一份好的測試用例數據,那麼,這麼多的數據,咱們要怎樣進行管理才能既不亂又方便之後對數據進行更改維護呢?下面,小編就要告訴朋友們一個重磅消息,敲黑板!!!
其實,小編也不知道有什麼好辦法,小編就是使用excel文件來對測試用例進行統一管理的。請看下面:
形式就是這麼個形式,內容就隨便大家怎麼修改了。畢竟我也只能幫大家到這裏了。至於對excel文件內容的讀取,在接口測試那篇博文中也有詳細介紹哦。不明白的同窗請移步:http://www.javashuo.com/article/p-koqjlcfy-ku.html
其實,出來測試用例,還有一個數量龐大的數據羣體,快猜猜它們是誰???
噹噹噹,答案就是:元素定位的數據,包括:id,name,classname,xpath等等,這些數據但是咱們在測試過程當中找到頁面元素的不二法門哦。。。因此各位朋友必定要注意啦,必定要處理好它們。
請看下面:
愚蠢的小編就用xml文件來管理啦。
是否是又有人想問怎麼讀取xml文件了?嘿嘿。。。我不會告訴你的,由於我在前面的博文裏已經講過啦!講過啦!過啦!啦!!
至此呢,今天的內容也結束了,但願對你們有所啓發和幫助,雖然講的有些凌亂,不過只要弄懂了這些劃分和實現方法,我相信,你也必定能夠寫出本身滿意的UI自動化測試框架。因此,咱們一塊兒加油吧。
PS:有些沒有提到的部分,因爲跟以前介紹接口自動化框架的內容同樣,因此就再也不累述,有想了解的朋友,移步此處便可。謝謝!http://www.javashuo.com/article/p-koqjlcfy-ku.html
本文爲原創文章,轉載請註明原文地址,謝謝你們的支持。但願你們一塊兒努力成長。