一、瀏覽器操作
1、瀏覽器最大化
driver.maximize_window() #將瀏覽器最大化顯示
2、設置瀏覽器寬、高
driver.set_window_size(480, 800)#設置瀏覽器寬480、高800顯示
3、控制瀏覽器前進、後退
driver.back()#瀏覽器後退
driver.forward()#瀏覽器前進
二、簡單對象的定位
webdriver 提供了一系列的元素定位方法,常用的有以下幾種:
- id
- name
- class name
- tag name
- link text
- partial link text
- xpath
- css selector
分別對應python webdriver 中的方法爲:
- find_element_by_id()
- find_element_by_name()
- find_element_by_class_name()
- find_element_by_tag_name()
- find_element_by_link_text()
- find_element_by_partial_link_text()
- find_element_by_xpath()
- find_element_by_css_selector()
1、id 和name 定位
id 和name 是我們最常用的定位方式,因爲大多數元素都有這兩個屬性,而且在對控件的id 和name
命名時一般使其有意義也會取不同的名字。通過這兩個屬性使我們找一個頁面上的屬性變得相當容易。
比如:
#id=”gs_htif0”
find_element_by_id("gs_htif0")
#name=”btnK”
find_element_by_name("btnK")
2、tag name 和class name 定位
比如:
#<div id="searchform" class="jhp_big" style="margin-top:-2px">
#<form id="tsf" οnsubmit="return name="f" method="GET" action="/search">
find_element_by_class_name("jhp_big")
find_element_by_tag_name("div")
tag name 定位應該是所有定位方式中最不靠譜的一種了,因爲在一個頁面中具有相同tag name 的元
素極其容易出現。
3、link text 與partial link text 定位
有時候需要操作的元素是一個文字鏈接,那麼我們可以通過link text 或partial link text 進行元素
定位。比如:
#通過link text 定位元素:
find_element_by_link_text("新聞")
find_element_by_link_text("貼吧")
find_element_by_link_text("一個很長的文字連接")
#通partial link text 也可以定位到上面幾個元素:
find_element_by_partial_link_text("新")
find_element_by_partial_link_text("吧")
find_element_by_partial_link_text("一個很長的")
當一個文字連接很長時,我們可以只取其中的一部分,只要取的部分可以唯一標識元素。一般一個頁
面上不會出現相同的文件鏈接,通過文字鏈接來定位元素也是一種簡單有效的定位方式。
4、XPath 定位
XPath 是一種在XML 文檔中定位元素的語言。因爲HTML 可以看做XML 的一種實現,所以selenium 用
戶可是使用這種強大語言在web 應用中定位元素。
以下面一段html代碼爲例:
<html class="w3c">
<body>
<div class="page-wrap">
<div id="hd" name="q">
<span id="input-container">
<input id="input" type="text" x-webkit-speech=""
autocomplete="off"
suggestwidth="501px" >
(1)使用絕對路徑定位:
當我們所要定位的元素很難找到合適的方式時,都可以通這種絕對路徑的方式位,缺點是當元素在很
多級目錄下時,我們不得不要寫很長的路徑,而且這種方式難以閱讀和維護。
find_element_by_xpath("/html/body/div[2]/form/span/input")
(2)使用相對路徑定位:
find_element_by_xpath("//input[@id=’input’]")
#通過自身的id 屬性定位
find_element_by_xpath("//span[@id=’input-container’]/input")
#通過上一級目錄的id 屬性定位
find_element_by_xpath("//div[@id=’hd’]/form/span/input")
#通過上三級目錄的id 屬性定位
find_element_by_xpath("//div[@name=’q’]/form/span/input")#通過上三級目錄的name 屬性定位
通過上面的例子,我們可以看到XPath 的定位方式非常靈活和強大的,XPath 可以做布爾邏輯運算,例如://div[@id=’hd’ or @name=’q’]。
當然,它的缺陷也非常明顯:
1、性能差,定位元素的性能要比其它大多數方式差;
2、不夠健壯,XPath會隨着頁面元素佈局的改變而改變;
3. 兼容性不好,在不同的瀏覽器下對XPath 的實現是不一樣的。
下面插播一下xpath的知識:
(1)路徑表達式:
表達式
|
描述
|
nodename
|
選取此節點的所有子節點。
|
/
|
從根節點選取。
|
//
|
從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
|
.
|
選取當前節點。
|
..
|
選取當前節點的父節點。
|
@
|
選取屬性。
|
實例
在下面的表格中,我們已列出了一些路徑表達式以及表達式的結果:
路徑表達式
|
結果
|
bookstore
|
選取 bookstore 元素的所有子節點。
|
/bookstore
|
選取根元素 bookstore。
註釋:假如路徑起始於正斜槓( / ),則此路徑始終代表到某元素的絕對路徑!
|
bookstore/book
|
選取屬於 bookstore 的子元素的所有 book 元素。
|
//book
|
選取所有 book 子元素,而不管它們在文檔中的位置。
|
bookstore//book
|
選擇屬於 bookstore 元素的後代的所有 book 元素,而不管它們位於 bookstore 之下的什麼位置。
|
//@lang
|
選取名爲 lang 的所有屬性。
|
實例
在下面的表格中,我們列出了帶有謂語的一些路徑表達式,以及表達式的結果:
路徑表達式
|
結果
|
/bookstore/book[1]
|
選取屬於 bookstore 子元素的第一個 book 元素。
|
/bookstore/book[last()]
|
選取屬於 bookstore 子元素的最後一個 book 元素。
|
/bookstore/book[last()-1]
|
選取屬於 bookstore 子元素的倒數第二個 book 元素。
|
/bookstore/book[position()<3]
|
選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。
|
//title[@lang]
|
選取所有擁有名爲 lang 的屬性的 title 元素。
|
//title[@lang='eng']
|
選取所有 title 元素,且這些元素擁有值爲 eng 的 lang 屬性。
|
/bookstore/book[price>35.00]
|
選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大於 35.00。
|
/bookstore/book[price>35.00]/title
|
選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00。
|
(2)選取未知節點
XPath 通配符可用來選取未知的 XML 元素。
通配符
|
描述
|
*
|
匹配任何元素節點。
|
@*
|
匹配任何屬性節點。
|
node()
|
匹配任何類型的節點。
|
實例
在下面的表格中,我們列出了一些路徑表達式,以及這些表達式的結果:
路徑表達式
|
結果
|
/bookstore/*
|
選取 bookstore 元素的所有子元素。
|
//*
|
選取文檔中的所有元素。
|
//title[@*]
|
選取所有帶有屬性的 title 元素。
|
5、CSS 定位
CSS(Cascading Style Sheets)是一種語言,它被用來描述HTML 和XML 文檔的表現。CSS 使用選擇器來爲頁面元素綁定屬性。這些選擇器可以被selenium 用作另外的定位策略。CSS 可以比較靈活選擇控件的任意屬性,一般情況下定位速度要比XPath 快,但對於初學者來說比較難以學習使用,下面我們就詳細的介紹CSS 的語法與使用:
例如下面一段代碼:
<div
class="formdiv"><form
name="fnfn"><input
name="username"
type="text"></input><input
name="password"
type="text"></input><input
name="continue"
type="button"></input><input
name="cancel"
type="button"></input><input
value="SYS123456"
name="vid"
type="text"><input
value="ks10cf6d6"
name="cid"
type="text"></form><div
class="subdiv"><ul
id="recordlist"><p>Heading</p><li>Cat</li><li>Dog</li><li>Car</li><li>Goat</li></ul></div></div>
通過CSS 語法進行匹配的實例:
關於自動化的定位問題:
自動化測試的元素定位一直是困擾自動化測試新手的一個障礙,因爲我們在自動化實施過程中會碰到
各式各樣的對象元素。雖然XPath 和CSS 可以定位到複雜且比較難定位的元素,但相比較用id 和name 來
說增加了維護成本和學習成本,相比較來說id/name 的定位方式更直觀和可維護,有新的成員加入的自動
化時也增加了人員的學習成本。所以,測試人員在實施自動化測試時一定要做好溝通,規範前端開發人員
對元素添加id/name 屬性,或者自己有修改HTML 代碼的權限。
三、操作測試對象
一般來說,所有有趣的操作與頁面交互都將通過WebElement 接口,包括上一節中介紹的對象定位,
以及本節中需要介紹的常對象操作。
webdriver 中比較常用的操作元素的方法有下面幾個:
- clear 清除元素的內容,如果可以的話
- send_keys 在元素上模擬按鍵輸入
- click 單擊元素
- submit 提交表單
例如:
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys("password")
driver.find_element_by_id("dl_an_submit").click()
#通過submit() 來提交操作
#driver.find_element_by_id("dl_an_submit").submit()
- clear() 用於清除輸入框的默認內容
- send_keys("xx") 用於在一個輸入框裏輸入xx 內容
- click() 用於單擊一個按鈕、連接等
- submit() 提交表單
1、WebElement 接口常用方法
WebElement 接口除了我們前面介紹的方法外,它還包含了別一些有用的方法。下面,我們例舉例幾
個比較有用的方法。
- size #返回元素的尺寸
- text #獲取元素的文本
- get_attribute(name) #獲得屬性值
- is_displayed() #檢查該元素是否用戶可見
例如:
size=driver.find_element_by_id("kw").size#返回百度輸入框的寬高
text=driver.find_element_by_id("cp").text
#返回百度頁面底部備案信息
#返回元素的屬性值,可以是id、name、type 或元素擁有的其它任意屬性
attribute=driver.find_element_by_id("kw").get_attribute('type')
#返回元素的結果是否可見,返回結果爲True 或False
result=driver.find_element_by_id("kw").is_displayed()
四、鼠標事件
前面例子中我們已經學習到可以用 click()來模擬鼠標的單擊操作,而我們在實際的 web 產品測試中發現,有關鼠標的操作,不單單隻有單擊,有時候還要和到右擊,雙擊,拖動等操作,這些操作包含在ActionChains 類中。
ActionChains 類鼠標操作的常用方法:
- context_click() 右擊
- double_click() 雙擊
- drag_and_drop() 拖動
- move_to_element() 鼠標懸停在一個元素上
- click_and_hold() 按下鼠標左鍵在一個元素上
1、右擊操作
...
#定位到要右擊的元素
right =driver.find_element_by_xpath("xx")
#對定位到的元素執行鼠標右鍵操作
ActionChains(driver).context_click(right).perform()
ActionChains 用於生成用戶的行爲;所有的行爲都存儲在 actionchains 對象中。通過 perform()執行存儲的行爲。
2、鼠標雙擊操作
...
#定位到要雙擊的元素
double =driver.find_element_by_xpath("xxx")
#對定位到的元素執行鼠標雙擊操作
ActionChains(driver).double_click(double).perform()
3、鼠標拖放操作
drag_and_drop(source, target)
在源元素上按下鼠標左鍵,然後移動到目標元素上釋放。
source: 鼠標按下的源元素。
target: 鼠標釋放的目標元素。
...
#定位元素的原位置
element = driver.find_element_by_name("xxx")
#定位元素要移動到的目標位置
target = driver.find_element_by_name("xxx")
#執行元素的移動操作
ActionChains(driver).drag_and_drop(element, target).perform()
4、鼠標移動上元素上
...
#定位到鼠標移動到上面的元素
above = driver.find_element_by_xpath("xxx")
#對定位到的元素執行鼠標移動到上面的操作
ActionChains(driver).move_to_element(above).perform()
5、按下鼠標左鍵
...
#定位到鼠標按下左鍵的元素
left=driver.find_element_by_xpath("xxx")
#對定位到的元素執行鼠標左鍵按下的操作
ActionChains(driver).click_and_hold(left).perform()
五、鍵盤事件
下面經常使用到的鍵盤操作:
- send_keys(Keys.BACK_SPACE) 刪除鍵(BackSpace)
- send_keys(Keys.SPACE) 空格鍵(Space)
- send_keys(Keys.TAB) 製表鍵(Tab)
- send_keys(Keys.ESCAPE) 回退鍵(Esc)
- send_keys(Keys.ENTER) 回車鍵(Enter)
- send_keys(Keys.CONTROL,'a') 全選(Ctrl+A)
- send_keys(Keys.CONTROL,'c') 複製(Ctrl+C)
- send_keys(Keys.CONTROL,'x') 剪切(Ctrl+X)
- send_keys(Keys.CONTROL,'v') 粘貼(Ctrl+V)
六、獲取頁面的title和url
有時間需要通過頁面的title和url去判斷頁面的狀態。比如測試登錄是否成功和重定向是否成功。
#獲得前面 title,打印
title = driver.title
print title
#獲得前面 URL,打印
now_url = driver.current_url
print now_url
七、設置等待時間
有時候爲了保證腳本運行的穩定性,需要腳本中添加等待時間。
設置等待時間有以下幾種方法:
- sleep(): 設置固定休眠時間。 python 的 time 包提供了休眠方法 sleep() , 導入 time包後就可以使用 sleep()進行腳本的執行過程進行休眠。
- implicitly_wait():是 webdirver 提供的一個超時等待。隱的等待一個元素被發現,或一個命令完成。如果超出了設置時間的則拋出異常。
- WebDriverWait():同樣也是 webdirver 提供的方法。在設置時間內,默認每隔一段時間檢測一次當前頁面元素是否存在,如果超過設置時間檢測不到則拋出異常。
1、sleep()休眠方法
當執行到sleep()方法時會固定休眠一定的時長,然後再往下執行。sleep()方法以秒爲單位,假如休眠時間小於 1 秒,可以用小數表示。
import time
....
time.sleep(5)
time.sleep(0.5)
當然,也可以直接導入 sleep()方法,使腳本中的引用更簡單
from time import
sleep
....
sleep(3)
sleep(30)
2、implicitly_wait()
隱式等待是通過一定的時長等待頁面上某元素加載完成。如果超出了設置的時長元素還沒被加載,則拋出NoSuchElementException異常。implicitly_wait()方法比 sleep() 更加智能,後者只能選擇一個固定的時間的等待,前者可以在一個時間範圍內智能的等待。以秒爲單位。注意:它並不針對頁面上的某一個元素進行等待,而是從你設定這個隱式等待開始的所有需要定位的元素。當腳本執行到某個元素定位時,如果元素可以定位,則繼續執行;如果元素定位不到,則它將以輪詢的方式不斷判斷元素是否定位到。超過設定時間拋出異常
#添加智能等待30秒
driver.implicitly_wait(30)
3、WebDriverWait()
詳細格式如下:
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None),參數解釋如下:
- driver - WebDriver 的驅動程序(Ie, Firefox, Chrome 或遠程)
- timeout - 最長超時時間,默認以秒爲單位
- poll_frequency - 休眠時間的間隔(步長)時間,默認爲 0.5 秒
- ignored_exceptions - 超時後的異常信息,默認情況下拋 NoSuchElementException 異常。
from selenium.webdriver.support.ui
import WebDriverWait
....
element = WebDriverWait(driver, 10).until(lambda
x: x.find_element_by_id(“someId”))
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id(“someId”).is_displayed())
WebDriverWai()一般由 unit()或 until_not()方法配合使用,下面是 unit()和 until_not()方法的說明:
until(method, message=’’)
調用該方法提供的驅動程序作爲一個參數,直到返回值不爲False。
until_not(method, message=’’)
調用該方法提供的驅動程序作爲一個參數,直到返回值爲 False。
八、定位一組對象
需要獲取頁面上的一組元素是的方法:
#find_elements 用於獲取一組元素。find_elements_by_id(‘xx’)
find_elements_by_name(‘xx’)
find_elements_by_class_name(‘xx’)
find_elements_by_tag_name(‘xx’)
find_elements_by_link_text(‘xx’)
find_elements_by_partial_link_text(‘xx’)
find_elements_by_xpath(‘xx’)
find_elements_by_css_selector(‘xx’)
可以使用for... in ...對這一組元素進行遍歷
for checkbox in
checkboxes:
checkbox.click()
我們獲取到一組元素之後也可以使用pop()方法獲得這一組元素中的第幾個,然後再對該元素進行操作:
find_elements_by_id(‘xx’).pop().click()
- pop()或pop(-1)默認獲取一組元素中的最後一個
- pop(0) 默認獲取一組元素的第一個元素
- pop(1) 默認獲取一組元素的第二個元素
- ......以此類推
九、層級定位
在實際的項目測試中,經常會有這樣的需求:頁面上有很多個屬性基本相同的元素 ,現在需要具體
定位到其中的一個。由於屬性基本相當,所以在定位的時候會有些麻煩,這時候就需要用到層級定位。先
定位父元素,然後再通過父元素定位子孫元素。
比如下拉列表,我們可以先點擊彈出下拉框然後再定位下拉列表中的選項
#點擊 Link1 鏈接(彈出下拉列表)
driver.find_element_by_link_text('Link1').click()
#在父親元件下找到 link 爲 Action 的子元素
menu =
driver.find_element_by_id('dropdown1').find_element_by_link_text('Another
action')
十、多表單切換
在 web 應用中經常會出現 frame/iframe 表單內嵌套的應用,WebDriver只能在一個頁面上進行元素識別定位,對於frame/iframe表單內嵌頁面上的元素無法直接定位。這是需要通過switch_to.frame()方法將當前定位的主體切換爲frame/iframe表單的內嵌頁面中。
driver.switch_to_frame("f2")
switch_to.frame()默認可以直接去表單的id或name屬性。如果沒有這兩個屬性,可以通過其他方式定位,比如:
#先通過xpath定位到iframe
xf=driver.find_element_by_xpath('/*[@class="if"]')
#再將定位對象傳給switch_to.frame()方法
driver.switch_to.frame()
如果完成了在當前表單上的操作,則可以通過switch_to.parent_content()方法跳出當前一集表單。該方法默認對應於離他最近的switch_to.frame()。如果要跳出最外層的頁面使用switch_to.default_conent().
十一、多窗口切換
1、相關方法
current_window_handle:獲得當前窗口句柄
window_handles:返回所有窗口的句柄到當前對話
switch_to.window(窗口句柄):切換到對應的窗口。
nowhandle=driver.current_window_handle
driver.find_element_by_link_text(u"發表話題").click()
time.sleep(3)
#由於發表新話題會新窗口打開,所以要指向新窗口,即發話題窗口
allhandles=driver.window_handles
for handle in
allhandles:
if(handle!=nowhandle):
driver.switch_to.window(handle)
十二、警告窗處理
處理javascript所生成的alert、confirm、prompt,可以使用switch_to_alert()方法定位到alert/confirm/prompt,然後使用text/accept/dismiss/send_keys等方法進行操作
- text 返回 alert/confirm/prompt 中的文字信息。
- accept 點擊確認按鈕。
- dismiss 點擊取消按鈕,如果有的話。
- send_keys 輸入值,這個 alert\confirm 沒有對話框就不能用了,不然會報錯。
十三、上傳文件
1、查找到input標籤,通過send_keys添加文件路徑
#通過查找到input標籤,然後send進去
driver.find_element_by_id("coverImgSrc").send_keys(u"%s"%tds["coverImgSrc"])
2、使用AutoIt識別flash控件和windows控件實現自動上傳文件
十四、調用javascript
當 webdriver 遇到沒法完成的操作時,筆者可以考慮借用 JavaScript 來完成。使用webdriver 提供的execute_script() 接口用來調用 js 代碼。比如要操作頁面上隱藏的元素,可以用javascript來把它設置爲可見然後進行操作
比如下面這段代碼:
使用javascript:
……
#修改元素的屬性
js = 'document.querySelectorAll("select")[0].style.display="block";'
driver.execute_script(js)
sel = driver.find_element_by_tag_name('select')
Select(sel).select_by_value('opel')
……
十五、控制瀏覽器滾動條
一般用到操作滾動條的會兩個場景:
- 註冊時的法律條文的閱讀,判斷用戶是否閱讀完成的標準是:滾動條是否拉到最下方。
- 要操作的頁面元素不在視覺範圍,無法進行操作,需要拖動滾動條
用於標識滾動條位置的代碼:
<body οnlοad= "document.body.scrollTop=0
">
<body οnlοad= "document.body.scrollTop=100000
">
如果滾動條在最上方的話, scrollTop=0 , 那麼要想使用滾動條在最可下方, 可以 scrollTop=100000 ,
這樣就可以使滾動條在最下方。
#將頁面滾動條拖到底部
js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(3)
#將滾動條移動到頁面的頂部
js1="var q=document.documentElement.scrollTop=0"
driver.execute_script(js1)
time.sleep(3)
十六、獲取元素對象的屬性值
有時候我們定位頁面上的元素髮現常用的id、name等屬性是相同的。這個時候我們只能通過常規的定位方法定位出一組元素,然後觀察通過元素的屬性可以定位出單個元素。可使用.get_attribute()方法。
比如:
# 選擇頁面上所有的 tag name 爲 input 的元素
inputs = driver.find_elements_by_tag_name('input')
#然後循環遍歷出 屬性data-node值 爲594434493的元素,單擊勾選for input
in inputs:
if input.get_attribute('data-node') ==
'594434493':
input.click()
……
十七、獲取驗證碼問題
關於驗證碼的處理,網上有幾種說法:
1、測試時先去掉驗證碼
2、使用驗證碼識別技術
3、使用cookies記錄登錄用戶名密碼,下次自動登錄免去驗證碼輸入環節
我們自己內部的處理方式是內部提供一個接口獲得驗證碼,然後通過js代碼把獲取的驗證碼填寫進去:
#自動獲取驗證碼並填寫
driver.execute_script(js)