Selenium是瀏覽器自動化工具,主要用來Web的自動化測試,以及基於Web的任務管理自動化。它支持的語言有:python、Java、ruby、JavaScript等,而且幾乎能在主流的瀏覽器上運行。css
Selenium2.0、Selenium3.0主要由三大部分組成:SeleniumIDE、Selenium WebDriver、Selenoium Grid。html
VS Selenium RC(Selenium1.0):在瀏覽器中運行javaScript,使用瀏覽器內置的JavaScript來翻譯和執行selensejava
Web Driver原理python
webDriver是按照client/server模式設計的。client是咱們的測試腳本,發送請求;server就是打開的瀏覽器,用來接收client的請求並做出響應。web
具體的工做流程:ajax
以web Driver用到的協議:設計模式
其中:瀏覽器
1)RC原理安全
在Selenium1.0中,是經過Selenium RC服務器做爲代理服務器去訪問應用從而達到測試的目的。ruby
Selenium RC分爲三個部分,Launcher、HttpProxy、Core。
然而直接運行JavaScript會有極大的安全漏洞,因此會受到「同源限制」,在這個基礎上,Selenium2.0引入了WebDriver。
2)Web Driver原理
webDriver是按照client/server模式設計的。client是咱們的測試腳本,發送請求;server就是打開的瀏覽器,用來接收client的請求並做出響應。
具體的工做流程:
因此web Driver用到的協議:
其中:
1)優化測試用例。
2)使用Selenium grid,經過testNG實現併發執行。
說到這裏,在編寫測試用例的時候,必定要實現鬆耦合,而後再服務器容許的狀況下,儘可能設置多線程實現併發運行。
3)設置等待時間、中斷頁面加載。若是頁面加載內容太多,咱們能夠查看一下加載緩慢的緣由,在不影響測試的狀況下,能夠設置超時時間,中斷頁面加載。
1. 誤報問題。咱們一旦測試用例沒有經過,則沒法完成每日自動構建,可是其實這些測試用例是正確,也不存在BUG。
2. 主要的緣由:頁面尚未加載完成,咱們就開始進行元素定位。
3. 解決方法:重試機制。利用遞歸封裝了一個等待元素的方法。其中,設置最大等待時間爲1s,輪詢時間爲50ms,這個方法會不斷輪詢,直到方法執行成功或者超過設置的最大等待時間。在咱們最好的一次實踐中,咱們把一個測試用例的誤報率從10%下降到0,而且執行時間從原先的45秒下降到33秒。
1. 使用四層結構實現業務邏輯、腳本、數據分離。
2. 使用PO設計模式,將一個頁面用到的元素和操做步驟封裝在一個頁面類中。若是一個元素定位發生了改變,咱們只用修改這個頁面的元素屬性
3. 對於頁面類的方法,咱們儘可能從客戶的正向邏輯去分析,方法中是一個獨立場景,例如:登陸到退出,並且不要想着把全部的步驟都封裝在一個方法中。
4. 測試用例設計中,減小測試用例之間的耦合度。
1. 一旦項目發生變化,測試用例就須要改進,工做量大。
2. 驗證的範圍有限,操做更加複雜,好比說簡單的一個驗證驗證碼,若是是人工識別很快就能夠輸入,可是自動化測試中會增添不少困難。那麼這個時候速度也不如人工。
3. 不穩定
4. 可靠性不強
5. 成本與收益
1)區分:display= none VS hidden
共同點:都把網頁中的元素給隱藏起來了;在selenium中沒法直接定位
區別:none:不爲隱藏的對象保留其物理空間 看不見/摸不着
hidden:仍佔有空間 看不見/摸得着
頁面主要經過"dislay:none"來控制整個下拉框不見。若是直接操做:
from selenium.webdriver.support.ui import WebDriverWait from selenium import webdriver from selenium.webdriver.support.select import Select import os driver = webdriver.Firefox(executable_path="/Users/lesley/Downloads/geckodriver") file_path = 'file:///' + os.path.abspath('test.html') driver.get(file_path) select = driver.find_elements('select') Select(select).select_by_value('volvo') WebDriverWait() driver.quit()
報錯:ElementNotVisible
咱們能夠通過JavaScript來修改display的值
js = 'document.querySelectortAll('select')[0]'.style.display='block';' select = driver.find_element_by_tag_name('select') Select(select).select_by_value('Opel')
document.querySelectAll('select'):選擇全部的select;[0]表示第幾個
style.display='block':修改display=block,表示可見
首先,判斷一個元素是否顯示:is_displayed()
frame是指:頁面中嵌入另外一個頁面,而webdriver每次只能在一個頁面識別,所以須要先定位到相應的frame,對那個頁面裏的元素進行定位。
此時,有兩種方式:
1. iframe存在id 或者name。
首先用switch_to_frame('x-URS-iframe')定位到這個iframe,而後再定位這個iframe中的元素
driver=webdriver.Firefox() driver.get(r'http://www.126.com/') driver.switch_to_frame('x-URS-iframe') #需先跳轉到iframe框架 username=driver.find_element_by_name('email') username.clear()
2. iframe不存在name/id。
先定位到iframe,再swith_to_frame
#先定位到iframe elementIframe= driver.find_element_by_class_name('APP-editor-iframe') #再將定位對象傳給switch_to_frame()方法 driver.switch_to_frame(elementIframe)
若是完成操做後,能夠經過switch_to_parent_content()方法跳出當前iframe,或者還能夠經過switch_to_default_content()方法跳回最外層的頁面。
獲取頁面加載狀態:
document.readyState
例如:當Selenium點擊一個按鈕打開一個彈窗,彈窗尚未打開的時候,咱們就要使用彈窗上一個按鈕。
——>解決:設置等待最大等待時間
1)sleep():設置固定休眠時間
2)implicity_wait():是webDriver提供的一個超時等待,隱的等待一個元素被發現,或者一個命令完成
3)WebDriverWait():一樣也是WebDriver提供的方法。在設置時間內,默認每隔一段時間檢測一次當前頁面元素是否存在,若是超出指定時間檢測不到則拋出異常。
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) # driver:WebDriver的驅動程序 # timeout:最長超時時間,默認以秒爲單位 # poll_frequency:休眠時間的間隔時間 # ignore_exception():超時後的異常信息,默認狀況下拋出NoSuchElementException
一般與until()或者until_not()方法配合使用
until(method, message="") # 調用該方法提供的驅動程序做爲一個參數,直到返回值不爲FALSE until_not(method, message="") # 調用該方法提供的驅動程序做爲一個參數,直到返回值爲FALSE
舉例:
1 from selenium.webdriver.support.ui import WebDriverWait 2 3 from selenium import webdriver 4 import time 5 6 driver = webdriver.Firefox(executable_path="/Users/lesley/Downloads/geckodriver") 7 driver.get("https://www.baidu.com/") 8 9 # 添加WebDriverWait 10 element = WebDriverWait(driver, 10).until(lambda driver:driver.find_element_by_id("kw")) 11 is_disappeared = WebDriverWait(driver, 5).until_not(lambda x: x.find_element_by_id("someId").is_displayed()) 12 element.send_keys("sbw") 13 14 # 添加智能等待 15 driver.implicitly_wait(5) 16 driver.find_element_by_id("su").click() 17 18 # 添加固定時間等待 19 time.sleep(5) 20 21 driver.quit()
4)WaitFor:配合setTimeout,設置最大等待時間,而後輪詢查看是否在指定時間內找到該元素。
1 def waitfor(getter, timeout=3, interval=0.5, *args): 2 starttime = datetime.datetime.now() 3 while True: 4 if getter(args): 5 return 6 else: 7 runtime = datetime.datetime.now() - starttime 8 print runtime 9 if runtime.seconds >= timeout: 10 raise Exception 11 time.sleep(interval) 12 13 current_value = 1 14 def testgetval(args): 15 wanted_value = args[0] 16 global current_value 17 current_value += 1 18 print '%d, %d' % (wanted_value, current_value) 19 return current_value > wanted_value 20 21 if __name__ == '__main__': 22 waitfor(testgetval, 1, 0.3, 2) 23 print '=======================' 24 waitfor(testgetval, 1, 0.3, 8)
如何判斷是動態ID?
簡單,通常看到元素屬性裏有拼接一串數字的,就頗有多是動態的。想要分辨,刷新一下瀏覽器再看該元素,屬性值中的數字串改變了,便是動態屬性了。
<div id="btn-attention_2030295">...</div>
方式(一)根據相對路徑
http://blog.csdn.net/huilan_same/article/details/52541680
方式(二)根據部分元素屬性定位
driver.find_element_by_xpath("//div[contains(@id, 'btn-attention')]") driver.find_element_by_xpath("//div[starts-with(@id, 'btn-attention')]") driver.find_element_by_xpath("//div[ends-with(@id, 'btn-attention')]") # 這個須要結尾是‘btn-attention’
——層級定位
# 點擊打開菜單欄 driver.find_element_by_xpath("//*[@id='sidebar-collapse']/i").click(); # 點擊菜單塊 driver.find_element_by_xpath("//*[@id='sidebar']/div[1]/ul/li[2]/a").click(); # 點擊「待辦中心」 driver.find_element_by_linkText("待辦案件").click();
driver.find_element_by_xpath("//span[contains(@id, 'sbw')] and not(contains[@style, 'display:none'])")
find_element_by_xpath("//標籤名[@屬性='屬性值']")
例如:
# id屬性: driver.find_element_by_xpath("//input[@id='kw']") # class屬性: driver.find_element_by_xpath("//input[@class='s_ipt']") # name屬性: driver.find_element_by_xpath("//input[@name='wd']") # maxlength屬性: driver.find_element_by_xpath("//input[@maxlength='255']")
driver.find_elment_by_xpath('//input')
3)父子定位元素
查找有父親元素的標籤名爲span,它的全部標籤名叫input的子元素
driver.find_element_by_xpath("//span/input")
例如:
<p id="jgwab"> <i class="c-icon-jgwablogo"></i> 京公網安備11000002000001號 </p>
則咱們能夠定位:
# 根據text()
driver.find_elment_by_xpath('//p[contains(text(), '京公網')]')
# 根據class
driver.find_elment_By_xpath('//p[contains(@class, '京公網')]')
//父元素標籤名/標籤名的屬性值:指的是span下的input標籤下class屬性爲s_ipt的元素
driver.find_element_by_xpath("//span/input[@class='s_ipt']")
指的是input標籤下id屬性爲kw且name屬性爲wd的元素
driver.find_element_by_xpath("//input[@class='s_ipt' and @name='wd']")
指的是p標籤下內容包含「京公網」且id屬性爲jgwab的元素
find_element_by_xpath("//p[contains(text(),'京公網') and @id='jgwab']")
element.click()
element.send_keys('test')
element.send_keys('D\test.txt')
#雙擊 ActionChains(driver).double_click(element).perform() #右擊 ActionChains(driver).context_click(element).perform() #拖動 ActionChains(driver).drag_and_drop(element).perform() #懸停 ActionChains(driver).move_to_element(element).perform()
from selenium.webdriver.support.ui import Select Select(driver.find_element_by_id('gender')).select_by_value('2') Select(driver.find_element_by_id('gender')).select_by_index(1) Select(driver.find_element_by_id('gender')).select_by_visible_text('Male')
Dropdown1 = driver.find_element_by_id(‘id’) #先定位到dropdown Dropdown1.find_element_by_id(「li2_input_2」) #再定位到dropdown中的值
3)使用js實現:
driver.switch_to_alert().accept() # 接收彈窗 driver.switch_to_alert().dismiss() # 取消彈窗 # 獲取彈窗的文本消息 Message = driver.switch_to_alert().text
driver.refresh() # 刷新 driver.back() # 後退 driver.forward() # 前進 driver.maximize_window() # 最大化 driver.set_window_size(100,200) # 設置窗口大小 driver.switch_to.window(searchwindow)
driver.switch_to.frame(ReferenceFrame) driver.switch_to.parent_frame() # frame須要一級一級切 driver.switch_to.default_content() # 返回最外層
:等到某個條件成立時繼續執行。每隔一段時間檢測,超出最大時間則拋出異常
is_disappeared = WebDriverWait(driver, 5).until_not(lambda x: x.find_element_by_id("someId").is_displayed())
隱式等待中的時間並不是一個固定的等待時間,它並不影響腳本的執行速度。好比進行某元素的定位時,若是元素能夠定位就繼續執行,若是目前定位不到就以輪詢的方式持續判斷該元素是否被定位到,若是超過規定的時間還沒定位到就拋出異常。
driver.implicitly_wait(20)
from time import sleep sleep(5)
3. selenium中如何保證操做元素的成功率?也就是說如何保證我點擊的元素必定是能夠點擊的?
Selenium有八種定位方式:
若是存在id,我必定使用Id,由於簡單方便,定位最快。其次是Xpath,由於不少狀況下html標籤的屬性不夠規範,沒法惟必定位。Xpath是經過相對位置定位
首先觸發動態事件,而後再定位。若是是動態菜單,則須要層級定位。——JS實現(對動態事件封裝)
http://www.cnblogs.com/tobecrazy/p/4817946.html
屬性動態變化也就是指該元素沒有固定的屬性值,能夠經過:
http://www.cnblogs.com/zhaozhan/archive/2009/09/10/1564332.html
不會的。因此有的時候,當selenium並未加載完一個頁面時再請求頁面資源,則會誤報不存在此元素。因此首先咱們應該考慮判斷,selenium是否加載完此頁面。其次再經過函數查找該元素。
1)斷言(assert):測試將會在檢查失敗時中止,並不運行後續的檢查
優勢:能夠直截了當的看到檢查是否經過
缺點:檢查失敗後,後續檢查不會執行,沒法收集那些檢查結果狀態
2)驗證(vertify):將不會終止測試
缺點:你必須作更多的工做來檢查測試結果:查看日誌——>耗時多,因此更偏向於斷言
# 斷言驗證:百度搜索的標題是否爲:百度搜索 # import unittest try: self.assertEqual(u"百度搜素", driver.title) except AssertionError as e: print("Cannot find this title")
3)Waitfor:用於等待某些條件變爲真。可用於AJAX應用程序的測試。
若是該條件爲真,他們將當即成功執行。若是該條件不爲真,則將失敗並暫停測試。直到超過當前所設定的超時時間。 通常跟setTimeout時間一塊兒用。
經常使用的斷言:
1 assertLocation # 判斷當前是在正確的頁面 2 assertTitle #檢查當前頁面的title是否正確 3 assertValue # 檢查input的值, checkbox或radio,有值爲」on」無爲」off」 4 assertSelected # 檢查select的下拉菜單中選中是否正確 5 assertSelectedOptions # 檢查下拉菜單中的選項的是否正確 6 assertText # 檢查指定元素的文本 7 assertTextPresent # 檢查在當前給用戶顯示的頁面上是否有出現指定的文本 8 assertTextNotPresent # 檢查在當前給用戶顯示的頁面上是否沒有出現指定的文本 9 assertAttribute # 檢查當前指定元素的屬性的值 10 assertTable # 檢查table裏的某個cell中的值 11 assertEditable # 檢查指定的input是否能夠編輯 12 assertNotEditable # 檢查指定的input是否不能夠編輯 13 assertAlert # 檢查是否有產生帶指定message的alert對話框 14 waitForElementPresent # 等待檢驗某元素的存在。爲真時,則執行。
不可以。Ajax是一種支持動態改變用戶界面元素的技術。在Ajax驅動的應用程序中,數據能夠從應用服務器檢索,而後顯示在頁面上,而不須要加載整個頁面,只有一小部分頁面或者元素自己被從新加載。
因此不可以使用ClickAndWait,由於Ajax call不會刷新整個頁面,clickAndWait命令會由於等待頁面從新加載而出現time out。
也就是說最大的麻煩是判斷Ajax調用是否結束。能夠用click + pause完成
使用JQuery進行輔助測試:http://www.cnblogs.com/nbkhic/archive/2011/10/23/2221729.html
其中,去哪兒網的題目以下:
1、 UI自動化測試
Qunar機票搜索場景
1) 訪問Qunar機票首頁http://flight.qunar.com,選擇「單程」,輸入出發、到達城市,選擇today+7往後的日期,點「搜索」,跳轉到機票單程搜索列表頁。
2) 在列表頁停留1分鐘,至到頁面上出現「搜索結束」。
3) 若是出現航班列表,對於出現「每段航班均需繳納稅費」的行隨機點選「訂票」按鈕,在展開的列表中會出現「第一程」、 「第二程」;
對於沒有出現「每段航班均需繳納稅費」的行隨機點選「訂票」按鈕,在展開的列表底部中會出現「報價範圍」
4) 若是不出現航班列表,則頁面會出現「該航線當前無可售航班」
請使用maven建立java工程,引入Selenium框架,編寫WebUI代碼,實現上述人工操做和驗證。要求能隨機驗證100個城市對的3個月內的任意搜索條件。
參見答案:http://www.cnblogs.com/tobecrazy/p/4752684.html
不少人可能第一步就卡住了,怎麼選擇7天之後的日期呢?
實際上很簡單,直接在輸入框裏輸入就行了。由於selenium支持的語言不少,這裏就用js寫一下。你們用selenium執行這段js就能夠搞定了。
var date = new Date(); date.setDate(date.getDate() + 7); var a_week_later = date.getFullYear() + '-' (date.getMonth()+1) + '-' + date.getDate(); $('input[name=fromDate]').val(a_week_later);
參考答案: http://www.cnblogs.com/tobecrazy/p/5873288.html