不一樣點 | selenium類(RF、Katalon、Macaca等) | UFT(QTP) | JS類庫(Phantomjs、CasperJS、Puppeteer) |
---|---|---|---|
是否開源 | 是 | 否 | 是 |
支持平臺 | Linux、Windows、Mac | Windows | Linux、Windows、Mac |
支持語言 | Python、Perl、PHP、C#等 | VB | JS |
支持瀏覽器 | ie、chrome、firefox、opera、safari | chrome、firefox、IE | PhantomJS、casperjS不支持、puppeteer:chrome |
支持錄製 | 支持 | 支持 | 不支持 |
python環境搭建php
下載python
驗證css
C:\Users\mac>python Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD 4)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>>
pip install selenium
pip show selenium
可以看到selenium的詳細信息則安裝成功html
Name: selenium Version: 3.13.0 Summary: Python bindings for Selenium Home-page: https://github.com/SeleniumHQ/selenium/ Author: UNKNOWN Author-email: UNKNOWN License: Apache 2.0 Location: /usr/local/lib/python2.7/site-packages Requires: Required-by:
注意:
1.瀏覽器版本必需要和驅動版本對應,不然會出現調用不起來瀏覽器或者沒法打開網頁的問題
2.在firefox48版本之前firefox是不須要瀏覽器驅動的,可是在firefox48之後須要下載對應版本的geckodriver驅動java
from selenium import webdriver driver=webdriver.Chrome() driver.get("http://www.so.com")
成功打開瀏覽器,而且打開指定網站,一般版本匹配就沒問題了node
優勢:快速、簡單
缺點:難維護
應用場景:適用於只須要完成當前任務,任務完成後再也不須要使用了,使用次數較少的場景python
目前selenium的錄製工具備兩種:
1.官方selenium ide
2.katalon recorder
推薦使用katalon recorder ,是katalon studio的子項目,具備比selenium ide更全面的功能git
下載安裝
進入chrome應用商店,搜索katalon recorder,進行安裝便可
https://chrome.google.com/webstore/category/extensions?hl=zh-CN
安裝成功後,右上角會有對應圖標github
頁面主要功能介紹:web
錄製實例:
測試步驟:
打開www.so.com
輸入框輸入:肯德基
點擊搜索按鈕
錄製過程:
1>點擊Record
2>瀏覽器輸入www.so.com
3>點擊輸入框
4>輸入肯德基
5>點擊搜索
6>點擊stopchrome
添加斷言
查看失敗截圖
回放
play:回放當前指定的case
play suite:回放當前case所在測試套件
play all:回放全部case
數據驅動
生成腳本
#導入selenium from selenium import webdriver #建立chrome驅動實例,打開瀏覽器 driver=webdriver.Chrome() #瀏覽器最大化 driver.maximize_window() #瀏覽器最小化 driver.minimize_window() #獲取瀏覽器當前窗口大小 size=driver.get_window_size() #設置瀏覽器窗口大小 driver.set_window_size(400,400) #打開指定網頁 driver.get("http://www.so.com") #獲取當前頁面的連接地址 url=driver.current_url driver.get("http://baike.so.com") #後退 driver.back() #前進 driver.forward() #瀏覽器退出 driver.close() driver.quit() #截圖 driver.get_screenshot_as_png() driver.get_screenshot_as_base64() driver.get_screenshot_as_file("filename") driver.save_screenshot("filename") #切換到當前被操做元素 ele=driver.switch_to.active_element #切換alert、confirm、prompt框 alert = driver.switch_to.alert #切換到默認頁面 driver.switch_to.default_content() #切換iframe driver.switch_to.frame('frame_name') driver.switch_to.frame(1) driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0]) driver.switch_to.parent_frame() #獲取瀏覽器全部句柄 handles=driver.window_handles #獲取當前句柄 current_handle=driver.current_window_handle driver.switch_to.window() #執行js腳本 driver.execute_script('script')
<input type="text" name="q" class="placeholder" id="input" suggestwidth="540px" autocomplete="off"> driver.find_element_by_id("input") driver.find_element_by_name("q") driver.find_element_by_class_name("placeholder") driver.find_element_by_tag_name("input") #經過link_text定位 <a href="http://www.so.com/link?m=aet4cncwddniEaPk6dHXguMLtzsuEZCshH9NOP1B83PNdna1JVlAE2E5xzKeyB2GUQSR9o8wo4KTK5n7ApE28%2FQ%3D%3D" data-url="http://ly.so.com/?src=tab_web" data-s="http://ly.so.com/s?q=%q%&src=tab_web" data-linkid="liangyi">良醫</a> driver.find_element_by_link_text("良醫") driver.find_element_by_partial_link_text("醫")
以上定位方式都是經過元素的特定屬性來定位的,若是一個元素它既沒有id、name、class屬性也不是超連接,這麼辦呢?或者說它的屬性不少重複的。還有時候標籤確實有id這個屬性,可是id又是以必定規則自動生成的,這個時候就能夠用xpath和css定位來解決。
具備很強的靈活性,同時使用也是相對複雜
常見符號:
#表示 id選擇器
.表示 class選擇器
>表示子元素,層級
一個空格也表示子元素,可是是全部的後代子元素
#<input type="text" name="q" class="placeholder" id="input" suggestwidth="540px" autocomplete="off"> #經過標籤訂位 driver.find_element_by_css_selector("input") #經過id定位 driver.find_element_by_css_selector("#input") #經過class定位 driver.find_element_by_css_selector(".placeholder") #經過屬性定位 driver.find_element_by_css_selector('[name="q"]') #以上都是單一形式的定位,上面的全部形式均可以進行組合定位 driver.find_element_by_css_selector("input#input") driver.find_element_by_css_selector("#input[name='q']")
XPath即爲XML路徑語言,它是一種用來肯定XML文檔中某部分位置的語言。通俗一點講就是經過元素的路徑來查找到這個元素
#xpath定位 #經過絕對路徑定位 #1.從html頁面的該元素的最頂層元素寫起 #2.以"/"分割每一層標籤 #下標從1開始 #不歸屬該元素的同級元素標籤不要寫 #優勢定位準確,可是一旦頁面有更改,則須要從新定位 driver.find_element_by_xpath("html/body/div[2]/div/section[2]/div/form/fieldset/div[2]/input") #經過相對路徑 #1.以雙"//"開頭 #2.只要能定位到目標元素的惟一路徑便可,不須要再向上查找 #3.路徑越短越好,避免由於寫的過長,致使頻繁更改定位方式 driver.find_element_by_xpath("//fieldset/div[2]/input") driver.find_element_by_xpath("//form/fieldset/div[2]/input") #經過標籤訂位:上面寫的都是經過標籤來進行的定位 #經過屬性定位(id,name,value,class等) #1.使用中括號將屬性名與屬性值放在一塊兒 #2.屬性名前面加上@符號表示 driver.find_element_by_xpath("//input[@name='q']") #經過索引定位
一般上面的方式基本上就能夠定位到元素,可是對於一些動態生成的元素,路徑重複性很高的元素,爲了不寫太長的路徑,有時候須要一些邏輯運算與xpath的函數來完成
#xpath中的邏輯運算(與或非) driver.find_element_by_xpath("//input[@name='q' and @ id='input']") #包含 contains函數 driver.find_element_by_xpath("//input[contains(@id,'input')]") #元素文本信息text函數 driver.find_element_by_xpath("//*[contains(text(),'醫')]") #starts-with函數 driver.find_element_by_xpath("//input[starts-with(@id,'inpu')]") #ends-with函數 driver.find_element_by_xpath("//input[ends-with(@id,'nput')]")
#清除文本框內容 input_element.clear() #點擊操做 input_element.click() #對文本框輸入 input_element.send_keys() #提交表單 input_element.submit() #獲取元素指定屬性的值 input_element.get_attribute("name") input_element.get_property("name") #獲取元素的大小 ele_size=input_element.size #獲取該元素的子元素 input_element.find_element() #判斷元素是否顯示 input_element.is_displayed() #判斷元素是否可使用 input_element.is_enabled() #判斷元素是不是選中狀態 input_element.is_selected() #查看元素的標籤名 input_tag=input_element.tag_name
#頁面滑動 js1="window.scrollTo(1000,1000)" js11='window.scrollTo(0,0)' js12='window,scrollTo(0,document.body.scrollHeight)' driver.execute_script("arguments[0].scrollIntoView();", input_element) #設置元素屬性:例如修改時間控件,設置頁面元素是否可見等,能夠省去不少selenium的步驟 js2='document.getElementById("XXX").setAttribute("placeholder","thisismyplaceholder")' #刪除元素屬性 js3='document.getElementById("XXX").removeAttribute("placeholder")' #元素操做操做:click,focus,blur等 js4='document.getElementById("xxx").click()' #元素定位 注意:這裏須要有return js5='return document.getElementById("xxx")'
click(on_element=None) ——單擊鼠標左鍵
click_and_hold(on_element=None) ——點擊鼠標左鍵,不鬆開
context_click(on_element=None) ——點擊鼠標右鍵
double_click(on_element=None) ——雙擊鼠標左鍵
drag_and_drop(source, target) ——拖拽到某個元素而後鬆開
drag_and_drop_by_offset(source, xoffset, yoffset) ——拖拽到某個座標而後鬆開
key_down(value, element=None) ——按下某個鍵盤上的鍵
key_up(value, element=None) ——鬆開某個鍵
move_by_offset(xoffset, yoffset) ——鼠標從當前位置移動到某個座標
move_to_element(to_element) ——鼠標移動到某個元素
move_to_element_with_offset(to_element, xoffset, yoffset) ——移動到距某個元素(左上角座標)多少距離的位置
perform() ——執行鏈中的全部動做
release(on_element=None) ——在某個元素位置鬆開鼠標左鍵
send_keys(*keys_to_send) ——發送某個鍵到當前焦點的元素
send_keys_to_element(element, *keys_to_send) ——發送某個鍵到指定元素
#導入鼠標事件 from selenium.webdriver.common.action_chains import ActionChains #雙擊 ActionChains(driver).double_click('target_element').perform() #右擊 ActionChains(driver).context_click("target_element").perform() #拖動 ActionChains(driver).drag_and_drop("start_element","end_element").perform() #鼠標移動到指定元素 ActionChains(driver).move_to_element("target_element").perform()
#彈出一個alert driver.execute_script("alert('helloworld')") #切換到alert my_alert=driver.switch_to.alert #獲取alert信息 alert_info=my_alert.text #點擊肯定 my_alert.accept() #點擊X my_alert.dismiss()
用例1:打開瀏覽器,打開指定頁面,查找元素,元素操做,斷言,關閉瀏覽器
用例2:打開瀏覽器,打開指定頁面,查找元素,元素操做,斷言,關閉瀏覽器
目的:
1.儘量少的打開瀏覽器
2.每一個case互不影響
3.減小重複性代碼
4.捕獲異常try...except...else....finaly
5.保留現場
6.用例須要有說明
分析:
import unittest from selenium import webdriver class TestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.driver=webdriver.Chrome() @classmethod def tearDownClass(cls): cls.driver.close() def setUp(self): self.driver.get("http://www.so.com") def tearDown(self): pass def test_case01(self): input_element=self.driver.find_element_by_id("input") input_element.send_keys("肯德基") search_botton=self.driver.find_element_by_id("search-button") search_botton.click() self.assertIn("肯德基" ,self.driver.title) def test_case02(self): input_element = self.driver.find_element_by_id("input") input_element.send_keys("麥當勞") search_botton = self.driver.find_element_by_id("search-button") search_botton.click() self.assertIn("麥當勞", self.driver.title) if __name__ == '__main__': unittest.main()
例1:測試須要運行ie8,9,10,11四個瀏覽器
例2:測試須要驗證同一個功能在同一個瀏覽器,可是在不一樣硬件配置上的執行狀況
問題:
1.一臺計算機沒辦法同時安裝4個ie,須要運行其餘安裝不一樣版本的機器
2.須要運行遠程機器上的瀏覽器
3.不一樣機器上的運行狀況須要上報給主機
selenium grid完美的解決了這些問題
#運行selenium服務 指定角色爲hub ,端口號爲4444 java -jar selenium-server-standalone-3.14.0.jar -role hub -port 4444
日誌信息也說明了,客戶端須要可以鏈接的機器名,子節點須要註冊到宿主節點
21:53:53.220 INFO [GridLauncherV3.launch] - Selenium build info: version: '3.14. 0', revision: 'aacccce0' 21:53:53.220 INFO [GridLauncherV3$2.launch] - Launching Selenium Grid hub on por t 4444 2018-09-02 21:53:53.594:INFO::main: Logging initialized @757ms to org.seleniumhq .jetty9.util.log.StdErrLog 21:53:53.842 INFO [Hub.start] - Selenium Grid hub is up and running 21:53:53.842 INFO [Hub.start] - Nodes should register to http://10.211.55.4:4444 /grid/register/ 21:53:53.842 INFO [Hub.start] - Clients should connect to http://10.211.55.4:444 4/wd/hub
第二步:啓動子節點而且註冊到宿主節點
java -jar selenium-server-standalone-3.14.0.jar -role node -port 5555 -hub http://10.211.55.4:4444/grid/register
日誌
22:00:47.753 INFO [GridLauncherV3.launch] - Selenium build info: version: '3.14. 0', revision: 'aacccce0' 22:00:47.753 INFO [GridLauncherV3$3.launch] - Launching a Selenium Grid node on port 5555 2018-09-02 22:00:47.945:INFO::main: Logging initialized @566ms to org.seleniumhq .jetty9.util.log.StdErrLog 22:00:48.116 INFO [SeleniumServer.boot] - Selenium Server is up and running on p ort 5555 22:00:48.116 INFO [GridLauncherV3$3.launch] - Selenium Grid node is up and ready to register to the hub 22:00:48.179 INFO [SelfRegisteringRemote$1.run] - Starting auto registration thr ead. Will try to register every 5000 ms. 22:00:48.179 INFO [SelfRegisteringRemote.registerToHub] - Registering the node t o the hub: http://10.211.55.4:4444/grid/register 22:00:48.537 INFO [SelfRegisteringRemote.registerToHub] - The node is registered to the hub and ready to use
第三步:代碼改造
from selenium import webdriver driver = webdriver.Remote( command_executor="http://127.0.0.1:5555/wd/hub",#指定遠程須要運行的節點 desired_capabilities={'browserName':"chrome"}#指定須要運行的瀏覽器 ) driver.get("http://www.so.com") driver.close()
1.頁面頻繁變更,致使自動化運行失敗,須要修改元素定位
2.一個元素在不少個case中使用,每次更改case須要把全部用到的地方都改一遍
3.case多了維護困難,根本不知道這個元素是哪一個地方的
1.頁面對象模型 (POM)是一種設計模式,用來管理維護一組元組集的對象庫
2.在 PO模式下,應用程序的 每個頁面都有對page class
3.每個 page class維護着該 web頁的元素集和操做這些方法
1.定位與測試用例分離,便於維護
2.用例更清晰,更易於閱讀
1.封裝driver
2.封裝base driver
3.封裝頁面
4.封裝頁面元素定位信息
5.編寫case
from selenium import webdriver from selenium.webdriver.common.by import By class GetDriver(): '''獲取瀏覽器驅動''' def __init__(self,browser_name): self.driver=self.__get_driver(browser_name) def __get_driver(self,browser_name): __browser_name=browser_name.lower() try: if __browser_name.lower()=="chrome": __driver=webdriver.Chrome() elif __browser_name.lower()=="firefox": __driver=webdriver.Firefox() else: raise Exception("沒有瀏覽器") except Exception as e: raise Exception("沒法驅動瀏覽器") else: return __driver class BasePage(): '''頁面基類''' def __init__(self,driver): self.driver=driver def get(self,url): try: self.driver.get(url) except: raise Exception("打開%s 頁面識別"%url) def find_element(self,page_name,type,location): try: element=self.driver.find_element(type,location) except: raise Exception("沒找到%s type=%s location=%s 這個元素"%(page_name,type,location)) else:return element class HomePageResource(): '''首頁頁面資源信息''' input={"page_name":"首頁","type":By.ID,"location":"input"} class HomePage(BasePage): '''首頁元素與操做''' def input(self): input_element=self.find_element(**HomePageResource().input) return input_element import unittest class TestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.driver=GetDriver("chrome").driver cls.home_page=HomePage(cls.driver) @classmethod def tearDownClass(cls): cls.driver.close() def setUp(self): self.home_page.get("http://www.so.com") def tearDown(self): pass def testcase01(self): self.home_page.input().send_keys("abc") if __name__ == '__main__': unittest.main()