Selenium 官網(wǎng)
Selenium WebDriver官網(wǎng)
webdriver實用指南python版本
WebDriver原理
WebDriver是按照Server-Client 的模式設(shè)計的。
Server就是 Remote Server,可以是任意的瀏覽器。當(dāng)我們的腳本啟動瀏覽器后,該瀏覽器就是Remote Server,她的職責(zé)就是等待 Client 發(fā)送請求并做出響應(yīng)。
Client 端簡單說就是我們寫的測試腳本。腳本中的一些行為比如打開瀏覽器,跳轉(zhuǎn)到指定的 URL 等操作就是以 http 請求的方式發(fā)送給被測試的瀏覽器,也就是Remote Server。Remote Server接受請求,執(zhí)行相應(yīng)操作,并在 Response中返回執(zhí)行狀態(tài)、返回值等信息。
Introducing WebDriver
作者注:WebDriver 可以看作是Selenium-RC替代品。所以現(xiàn)在學(xué)習(xí) Selenium 就不需要花時間專注于Selenium-RC了。
Selenium 2.0的主要新特性是WebDriver API的集成。WebDriver旨在提供一個更簡單、更簡潔的編程接口,以解決Selenium-RC API的一些限制。Selenium-WebDriver是為了更好地支持動態(tài)web頁面而開發(fā)的,頁面的元素在沒有頁面本身被重新加載的情況下可能會發(fā)生變化。WebDriver的目標(biāo)是提供一個設(shè)計良好的面向?qū)ο蟮腁PI,為現(xiàn)代高級web應(yīng)用程序測試問題提供改進(jìn)的支持。
Selenium RC(Selenium 3.0版本移除了該模塊,以后還是使用 WebDriver 進(jìn)行腳本的編寫) 由Clent Libraies 和 Selenium Server組成:
Selenium Libraies 用于編寫測試腳本,支持多種不同的主流開發(fā)語言,用來控制Selenium Server.
Selenium Server 則負(fù)責(zé)控制瀏覽器的行為,而Selenium Server 又由三部分組成:
Selenium Core:被Selenium Server 嵌入到瀏覽器頁面中,是一堆的JavaScript 函數(shù)的集合,通過這些JavaScript函數(shù)來實現(xiàn)對瀏覽器的操作。
Launcher:用于啟動瀏覽器,把Selenium Core加載到瀏覽器頁面當(dāng)中,并把瀏覽器的代理設(shè)置Selenium Server 的Http Proxy。
Http Proxy:Selenium Server的http代理。
??
How Does WebDriver ‘Drive’ the Browser Compared to Selenium-RC?
Selenium-WebDriver使用每個瀏覽器對自動化的本地支持直接調(diào)用瀏覽器。這些直接調(diào)用是如何生成的,它們支持的特性取決于您使用的瀏覽器。本章稍后將提供關(guān)于每個“瀏覽器驅(qū)動程序”的信息。
對于那些熟悉Selenium-RC的人來說,這與您所習(xí)慣的完全不同。Selenium-RC對每個支持的瀏覽器都使用相同的方法。它在瀏覽器加載時將javascript函數(shù)注入瀏覽器,然后使用javascript在瀏覽器中驅(qū)動AUT。WebDriver不使用這種技術(shù)。同樣,它直接驅(qū)動瀏覽器使用內(nèi)置的支持自動化的瀏覽器。
??
WebDriver and the Selenium-Server
您可能,也可能不需要Selenium服務(wù)器,這取決于您打算如何使用Selenium- webdriver。如果您的瀏覽器和測試都運(yùn)行在同一臺機(jī)器上,并且您的測試只使用WebDriver API,那么您就不需要運(yùn)行selenium服務(wù)器;WebDriver將直接運(yùn)行瀏覽器。
不過,有一些原因可以使用selenium服務(wù)器和Selenium-WebDriver。
- 您正在使用Selenium-Grid在多臺機(jī)器或虛擬機(jī)(vm)上分發(fā)測試。
- 您希望連接到具有特定瀏覽器版本的遠(yuǎn)程機(jī)器,而不是當(dāng)前機(jī)器上的。
- 您沒有使用Java綁定(例如Python、c#或Ruby),并希望使用 HtmlUnit Driver。
Setting Up a Selenium-WebDriver Project
安裝Selenium意味著在開發(fā)中建立項目,這樣您就可以使用Selenium編寫程序。如何做到這一點取決于您的編程語言和開發(fā)環(huán)境。
這里只介紹如何將Selenium添加到Python環(huán)境
pip install selenium
或者是:
pip3 install selenium
Pip需要安裝 pip, Pip也依賴于 setuptools。
至于如何將Selenium添加到其他語言環(huán)境中,請查閱Selenium WebDriver官網(wǎng)。
至于已經(jīng)在使用 Selenium1.0的同學(xué)們?nèi)绾无D(zhuǎn)為使用Selenium WebDriver。請看官網(wǎng)介紹
??
Introducing the Selenium-WebDriver API by Example
WebDriver是一種用于自動化web應(yīng)用程序測試的工具,特別是用于驗證它們是否按預(yù)期工作。它的目標(biāo)是提供一個友好的API,易于探索和理解,比Selenium-RC (1.0) API更容易使用,這將有助于使您的測試更容易閱讀和維護(hù)。它不依賴于任何特定的測試框架,因此它可以在單元測試項目中或從簡單的舊的“main”方法中使用。本節(jié)介紹WebDriver的API,并幫助您熟悉它。如果您還沒有建立一個WebDriver項目,那就開始吧。這在前面的小節(jié)中描述過,設(shè)置了一個Selenium-WebDriver項目。
一旦您的項目建立起來,您可以看到WebDriver就像任何普通的庫一樣:它是完全自包含的,而且您通常不需要記住在使用它之前啟動任何其他進(jìn)程或運(yùn)行任何安裝程序,而不是使用Selenium-RC的代理服務(wù)器。
注意: 使用 ChromeDriver, Opera Driver, Android Driver 以及 iOS Driver需要額外配置
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
# Create a new instance of the Firefox driver
driver = webdriver.Firefox()
# go to the google home page
driver.get("http://www.google.com")
# the page is ajaxy so the title is originally this:
print driver.title
# find the element that's name attribute is q (the google search box)
inputElement = driver.find_element_by_name("q")
# type in the search
inputElement.send_keys("cheese!")
# submit the form (although google automatically searches now without submitting)
inputElement.submit()
try:
# we have to wait for the page to refresh, the last thing that seems to be updated is the title
WebDriverWait(driver, 10).until(EC.title_contains("cheese!"))
# You should see "cheese! - Google Search"
print driver.title
finally:
driver.quit()
其他腳本語言示例請參考。
??
Selenium-WebDriver API Commands and Operations
??Fetching a Page(獲取某個頁面)
你可能想要做的第一件事是導(dǎo)航到一個頁面。通常的方法是通過調(diào)用get:
driver.get("http://www.google.com")
該腳本為 Python 腳本,其他語言腳本請參考。
依賴于幾個因素,包括操作系統(tǒng)/瀏覽器組合,WebDriver可能會等待頁面加載。在某些情況下,WebDriver可以在頁面完成甚至開始加載之前返回控件。為了確保健壯性,您需要等待在頁面中使用 Explicit and Implicit Waits。
解釋:因為網(wǎng)絡(luò)環(huán)境的因素,每個頁面每次加載的時間會有所不同,如果在某一個頁面加載出來之前,腳本即執(zhí)行該頁面的某一個元素,則會報錯。所以為了確保頁面已經(jīng)加載完畢再執(zhí)行,所以我們會在必要的時候使用 wait 命令。
??Locating UI Elements (WebElements)
在WebDriver中定位元素可以在WebDriver實例本身或WebElement上完成。每個語言綁定公開一個 “Find Element” and “Find Elements” 方法。前者返回與查詢匹配的WebElement對象,如果不能找到該元素,則拋出異常。后者返回一個WebElements列表,如果沒有DOM元素匹配查詢,則可能為空。
“Find”方法采用名為“By”的定位器或查詢對象。下面列出了“策略”。
作者注:DOM屬性
DOM 是 W3C(萬維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn)。
屬性是節(jié)點(HTML 元素)的值,您能夠獲取或設(shè)置。
??By ID
這是定位一個元素最有效的方法。UI開發(fā)人員所犯的常見錯誤是在頁面上有非惟一id,或者自動生成id,這兩個都應(yīng)該避免。html元素上的類比自動生成的id更合適。
如果待測元素的源碼如下所示,我們該如何定位呢:
<div id="coolestWidgetEvah">...</div>
解釋:此處我們假設(shè)該元素是一個按鈕。該元素的 id 即為coolestWidgetEvah。就可以通過 id 定位到該元素。除非某個元素沒有 id 這個屬性,一般我們都使用 id 定位元素。
以下使用 id定位 元素為 Python 腳本示例:
element = driver.find_element_by_id("coolestWidgetEvah")
或者
from selenium.webdriver.common.by import By
element = driver.find_element(by=By.ID, value="coolestWidgetEvah")
解釋:通過這兩個方法均可以定位到該按鈕,并將該方法返回的值賦值給變量 element,以便進(jìn)行其他操作。
其他語言腳本示例請參考
??By Class Name
本例中的“類”是指DOM元素上的屬性。通常在實際使用中,有許多具有相同類名的DOM元素,因此,查找第一個元素時,找到多個元素成為更實際的選擇。
類似下面的待測 web 頁面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br>
<div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div>
解釋:該元素的 class(類)即 cheese。
Python 腳本如下:
cheeses = driver.find_elements_by_class_name("cheese")
或者
from selenium.webdriver.common.by import By
cheeses = driver.find_elements(By.CLASS_NAME, "cheese")
其他語言腳本請參考。
??By Tag Name
元素的DOM標(biāo)記名。
類似下面的待測 web 頁面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br>
<iframe src="..."></iframe>
Python 示例:
frame = driver.find_element_by_tag_name("iframe")
或者
from selenium.webdriver.common.by import By
frame = driver.find_element(By.TAG_NAME, "iframe")
其他腳本語言示例請參考。
通過 tag 識別某個元素的概率很低,例如我們打開任意一個頁面,查看前端都會發(fā)現(xiàn)大量的<div>、<input>、<a>等等 tag。除非一個頁面只有這一個沒有重復(fù)的 tag,比如上述示例,<iframe>就是很少用的一個 tag,如果一個頁面中只有這么一個<iframe>tag 那么就可以用 tag 定位。
??By Name
找到具有匹配名稱屬性的輸入元素。
類似下面的待測 web 頁面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br>
<input name="cheese" type="text"/>
以下為 Python 示例:
cheese = driver.find_element_by_name("cheese")
或者
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.NAME, "cheese")
其他腳本語言示例請參考。
??By Link Text
找到與可見文本匹配的鏈接元素。
類似下面的待測 web 頁面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br>
<a >cheese</a>>
以下為 Python 示例:
cheese = driver.find_element_by_link_text("cheese")
或者
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.LINK_TEXT, "cheese")
比如百度主頁頂部的一行鏈接,如圖:
如果想要點擊“新聞”這個鏈接,那么就使用這個定位方法。
其他腳本語言示例請參考。
??By Partial Link Text
找到帶有部分匹配可見文本的鏈接元素。
類似下面的待測 web 頁面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br>
<a >search for cheese</a>>
以下為 Python 示例:
cheese = driver.find_element_by_partial_link_text("cheese")
或者
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.PARTIAL_LINK_TEXT, "cheese")
比如百度主頁底部有一個比較長的鏈接,如圖:
這個鏈接的完整文本是“京公網(wǎng)安備11000002000001號”,我們使用部分文本,比如“京公網(wǎng)”就可以唯一確定是這個鏈接。此時就可以使用該定位方法。
??By CSS
顧名思義,它是css的定位策略。默認(rèn)情況下使用本機(jī)瀏覽器支持,所以請參考w3c css selectors,以獲得一般可用的css選擇器列表。如果瀏覽器沒有對css查詢的本機(jī)支持,則使用 Sizzle。IE6、7和FF3.0目前使用Sizzle作為css查詢引擎。
要注意的是,并非所有的瀏覽器都是相同的,有些css可能在一個版本中工作,但在另一個版本中可能無效。
比如下面查找“cheese”這個元素:
<div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>
python腳本示例:
cheese = driver.find_element_by_css_selector("#food span.dairy.aged")
解釋一下這個定位方法:
- #表示通過 id 屬性定位元素,因為 food 是一個 id 屬性值,所以前面加一個#號;
- 通過標(biāo)簽名定位元素前面不加任何符號標(biāo)識,直接使用標(biāo)簽名即可,因為 span 是一個標(biāo)簽名,所以前面什么都不加;
- . 表示通過 class 屬性定位元素,因為 dairy 是一個 class 屬性值,所以前面加一個.號。
這個腳本用的是多種方式的組合。通過一級級標(biāo)簽進(jìn)行最終的定位。我們還以百度主頁為例進(jìn)行舉例說明。
比如通過 class 屬性定位到輸入框 這個元素:
find_element_by_css_selector(".s_ipt")
比如通過 id 屬性定位到輸入框這個元素:
find_element_by_css_selector("#kw")
比如通過標(biāo)簽名定位(當(dāng)然這里不適用,標(biāo)簽名<input>不唯一):
find_element_by_css_selector("input")
通過組合定位就是:
find_element_by_css_selector("input#kw")
注意:這里 class 和 id 兩個屬性是同一級標(biāo)簽下的屬性,只使用一個。
為了更精確的定位,我們還可以使用剛精確的定位方式:
find_element_by_css_selector("div span input#kw")
這種組合方式還有很多,再舉一例:
browser.find_element_by_css_selector("form.fm span.bg.s_ipt_wr.quickdelete-wrap input.s_ipt").send_keys(u"簡書")
注意: 最后在輸入框輸入漢字的時候在漢字前加了一個字母 u,如果不加則會造成漢字無法識別的錯誤
或者
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.CSS_SELECTOR, "#food span.dairy.aged")
??By XPath
在高層次上,WebDriver盡可能使用瀏覽器的本地XPath功能。在那些沒有本地XPath支持的瀏覽器上,我們提供了自己的實現(xiàn)。這可能導(dǎo)致一些意外的行為,除非您意識到不同的XPath引擎之間的差異。(總之一句話,不到別無選擇,不推薦使用 XPath 定位)。
Driver | Tag and Attribute Name | Attribute Values | Native XPath Support |
---|---|---|---|
HtmlUnit Driver | Lower-cased | As they appear in the HTML | Yes |
Internet Explorer Driver | Lower-cased | As they appear in the HTML | No |
Firefox Driver | Case insensitive | As they appear in the HTML | Yes |
這是一個有點抽象的東西,所以對于下面這段HTML:
<input type="text" name="example" />
<INPUT type="text" name="other" />
python 腳本示例:
inputs = driver.find_elements_by_xpath("http://input")
或者
from selenium.webdriver.common.by import By
inputs = driver.find_elements(By.XPATH, "http://input")
將會找到以下的匹配數(shù):
XPath expression | HtmlUnit Driver | Firefox Driver | Internet Explorer Driver |
---|---|---|---|
//input | 1 (“example”) | 2 | 2 |
//INPUT | 0 | 2 | 0 |
有時,HTML元素不需要顯式地聲明屬性,因為它們將默認(rèn)為已知值。例如,“input”標(biāo)簽不需要“type”屬性,因為它默認(rèn)為“text”。在WebDriver中使用xpath時的經(jīng)驗法則是,您不應(yīng)該期望能夠與這些隱式屬性相匹配。
這里介紹一下“絕對路徑定位”方法,這個方法在定位元素走投無路的時候或許能幫助你。我們還是以百度首頁的輸入框為例,如下圖:
如果這個輸入框元素的屬性沒有 id,沒有 class,沒有name。咋辦,使用 tag 定位?你可以看到這個頁面不止一個<input>,不具有唯一性,所以無法使用 tag 定位。此時就可以使用絕對路徑定位。腳本如下:
find_element_by_xpath("/html/body/div/div[1]/div/div/div/form/span/input")
看起來就有點暈,我來解釋一下。
這里是通過標(biāo)簽定位,必須要從<html>開始。<html>的下一級標(biāo)簽有<head>和<body>,這兩個標(biāo)簽是平級的,沒有父子之分,因為我們要定位的元素在標(biāo)簽<body>下,所以<html>之后是<body>。<body>之后又有兩個平級標(biāo)簽<script>和<div>,我們選擇<div>。但是這個<div>標(biāo)簽之后有多個平級標(biāo)簽<div>,上面截圖沒有體現(xiàn),看下圖:
。
這個標(biāo)簽下有很多平級標(biāo)簽均未<div>,而我們要找的是第一個<div>,所以是<div>[1]。以此類推,直達(dá)定位到目標(biāo)元素。
注意:這種定位方法不到萬不得已不使用,因為一旦頁面有一點改動,定位就可能會出錯。
??Using JavaScript
您可以執(zhí)行任意的javascript來找到一個元素,只要返回一個DOM元素,它就會自動轉(zhuǎn)換成一個WebElement對象。
在具有jQuery的頁面上的簡單示例:
java示例:
WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]");
python 示例:
element = driver.execute_script("return $('.cheese')[0]")
查找頁面上每個標(biāo)簽的所有輸入元素:
java示例:
List<WebElement> labels = driver.findElements(By.tagName("label"));
List<WebElement> inputs = (List<WebElement>) ((JavascriptExecutor)driver).executeScript(
"var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
"inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels);
python 示例:
labels = driver.find_elements_by_tag_name("label")
inputs = driver.execute_script(
"var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
"inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels)
??Getting text values
人們通常希望檢索元素中包含的innerText值。這會返回單個字符串值。注意,這只會返回頁面上顯示的可見文本。
python 示例:
element = driver.find_element_by_id("element_id")
element.text
??User Input - Filling In Forms
我們已經(jīng)看到了如何將文本輸入到文本區(qū)域或文本字段中,但是其他元素又如何呢?您可以“切換”復(fù)選框的狀態(tài),您可以使用“click”設(shè)置一些類似于選擇的選項標(biāo)記。處理選擇標(biāo)簽并不是很糟糕:
Python 腳本示例:
select = driver.find_element_by_tag_name("select")
allOptions = select.find_elements_by_tag_name("option")
for option in allOptions:
print "Value is: " + option.get_attribute("value")
option.click()
這將在頁面上找到第一個“SELECT”元素,然后依次遍歷每個選項,打印出它們的值,然后依次選擇它們。您會注意到,這并不是處理SELECT元素的最有效方法。WebDriver的支持類包括一個名為“Select”的類,它提供了與這些類交互的有用方法。
python
# available since 2.12
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_tag_name("select"))
select.deselect_all()
select.select_by_visible_text("Edam")
這將從頁面上的第一個SELECT中取消所有選項,然后選擇帶有“Edam”的顯示文本的選項。
填寫完表單后,您可能需要提交它。一種方法是找到“提交”按鈕并點擊它:
python
driver.find_element_by_id("submit").click()
Alternatively, WebDriver has the convenience method “submit” on every element. If you call this on an element within a form, WebDriver will walk up the DOM until it finds the enclosing form and then calls submit on that. If the element isn’t in a form, then the NoSuchElementException will be thrown:
python
element.submit()
??Moving Between Windows and Frames
一些web應(yīng)用程序有許多框架或多個窗口。WebDriver支持使用“切換”方法在指定的窗口之間移動:
driver.switch_to.window("windowName")
所有對驅(qū)動程序的調(diào)用將被解釋為指向特定的窗口。但是你怎么知道窗戶的名字呢?看一下打開的javascript或鏈接:
<a href="somewhere.html" target="windowName">Click here to open a new window</a>
或者,您可以將“窗口句柄”傳遞給“切換().window()”方法。知道了這一點,就可以遍歷每個打開的窗口:
python
for handle in driver.window_handles:
driver.switch_to.window(handle)
作者注:HANDLE(句柄)是Windows操作系統(tǒng)中的一個概念。在Windows程序中,有各種各樣的資源(窗口、圖標(biāo)、光標(biāo)等),系統(tǒng)在創(chuàng)建這些資源時會為它們分配內(nèi)存,并返回標(biāo)示這些資源的標(biāo)示號,即句柄。(摘自互動百科)
??Popup Dialogs
從Selenium 2.0 beta 1開始,構(gòu)建了支持處理彈出對話框的支持。在您觸發(fā)一個打開彈出窗口的操作之后,您可以通過以下方式訪問警報:
python
alert = driver.switch_to.alert
# usage: alert.dismiss(), etc.
這將返回當(dāng)前打開的警告對象。通過這個對象,您現(xiàn)在可以接受、解散、讀取它的內(nèi)容,甚至可以鍵入一個提示符。這個接口在警報、確認(rèn)和提示上同樣有效。更多信息請參考JavaDocs或RubyDocs。
??Navigation: History and Location
早些時候,我們使用“get”命令(driver.get(“http://www.example.com”)或driver.Url=“http://www.example.com”在c#中導(dǎo)航到一個頁面。如您所見,WebDriver有許多較小的、面向任務(wù)的接口,導(dǎo)航是一項有用的任務(wù)。因為加載頁面是一個基本的要求,所以在主WebDriver接口上執(zhí)行這個操作的方法,但是它只是一個同義詞:
python
driver.get("http://www.example.com") # python doesn't have driver.navigate
重申:“導(dǎo)航(). To()”和“get()”做完全相同的事情。一個人比另一個更容易打字!
“導(dǎo)航”界面也暴露了在瀏覽器的歷史中來回移動的能力:
python
driver.forward()
driver.back()
請注意,此功能完全依賴于底層瀏覽器。如果你習(xí)慣了一個瀏覽器的行為,那么你調(diào)用這些方法時可能會發(fā)生意想不到的事情。
??Cookies
在我們開始下一步內(nèi)容之前,您可能會對如何使用cookie感興趣。首先,您需要在cookie將有效的域上。如果你想在開始與網(wǎng)站交互之前預(yù)設(shè)cookie,而你的主頁是大的/需要一段時間來加載另一種選擇,那就是在網(wǎng)站上找到一個較小的頁面(通常是404頁面很小,例如http://example.com/some404page)。
Python
# Go to the correct domain
driver.get("http://www.example.com")
# Now set the cookie. Here's one for the entire domain
# the cookie name here is 'key' and its value is 'value'
driver.add_cookie({'name':'key', 'value':'value', 'path':'/'})
# additional keys that can be passed in are:
# 'domain' -> String,
# 'secure' -> Boolean,
# 'expiry' -> Milliseconds since the Epoch it should expire.
# And now output all the available cookies for the current URL
for cookie in driver.get_cookies():
print "%s -> %s" % (cookie['name'], cookie['value'])
# You can delete cookies in 2 ways
# By name
driver.delete_cookie("CookieName")
# Or all of them
driver.delete_all_cookies()
??Changing the User Agent
這對于Firefox Driver來說很簡單:
python
profile = webdriver.FirefoxProfile()
profile.set_preference("general.useragent.override", "some UA string")
driver = webdriver.Firefox(profile)
??Drag And Drop
這里有一個使用action類來執(zhí)行拖放操作的示例。必須啟用本地事件。
python
from selenium.webdriver.common.action_chains import ActionChains
element = driver.find_element_by_name("source")
target = driver.find_element_by_name("target")
ActionChains(driver).drag_and_drop(element, target).perform()
??
Driver Specifics and Tradeoffs
Selenium-WebDriver’s Drivers
WebDriver是測試應(yīng)該編寫的關(guān)鍵接口的名稱,但是有幾個實現(xiàn)。這些包括:
??HtmlUnit Driver
這是目前最快速、最輕量級的WebDriver實現(xiàn)。顧名思義,這是基于HtmlUnit的。HtmlUnit是一個沒有GUI的基于java的WebBrowser實現(xiàn)。對于任何語言綁定(除了java), Selenium服務(wù)器都需要使用這個驅(qū)動程序。
????Usage
python
driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNIT.copy())
????Pros
- 最快的實現(xiàn)WebDriver
- 純Java解決方案,因此它是平臺無關(guān)的。
- 支持JavaScript.
????Cons
- 模擬其他瀏覽器的JavaScript行為(見下面)
????JavaScript in the HtmlUnit Driver
沒有一個流行的瀏覽器使用HtmlUnit (Rhino)使用的JavaScript引擎。如果您使用HtmlUnit測試JavaScript,結(jié)果可能與那些瀏覽器有很大不同。
當(dāng)我們說“JavaScript”時,實際上是指“JavaScript和DOM”。雖然DOM是由W3C定義的,但是每個瀏覽器都有自己的特性和在DOM的實現(xiàn)上的差異,以及JavaScript如何與DOM交互。HtmlUnit有一個令人印象深刻的完整實現(xiàn)使用JavaScript DOM和具有良好的支持,但它是沒有不同于其他任何瀏覽器:它有自己的怪癖和差異來自W3C標(biāo)準(zhǔn)和主流瀏覽器的DOM實現(xiàn),盡管其模仿其他瀏覽器的能力。
有了WebDriver,我們必須做出選擇;我們是否啟用了HtmlUnit的JavaScript功能,并運(yùn)行那些只出現(xiàn)在那里的問題的團(tuán)隊的風(fēng)險,或者我們是否禁用了JavaScript,知道有越來越多的站點依賴于JavaScript?我們采用了保守的方法,默認(rèn)情況下在使用HtmlUnit時禁用了支持。隨著WebDriver和HtmlUnit的每個版本的發(fā)布,我們重新評估這個決定:我們希望在HtmlUnit上默認(rèn)啟用JavaScript。
????Enabling JavaScript
If you can’t wait, enabling JavaScript support is very easy:
Python
driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNITWITHJS)
這將導(dǎo)致HtmlUnit驅(qū)動程序在默認(rèn)情況下模擬Firefox 3.6的JavaScript處理。
??Firefox Driver
使用Firefox插件控制 Firefox瀏覽器。使用的Firefox配置文件從安裝在機(jī)器上的內(nèi)容剝離出來,只包含了Selenium WebDriver。xpi(插件)。默認(rèn)情況下,一些設(shè)置也會發(fā)生變化(參見源代碼,看看哪些是Firefox驅(qū)動程序),F(xiàn)irefox驅(qū)動程序可以在Windows、Mac和Linux上進(jìn)行測試。目前版本3.6, 10, latest - 1, latest。
????Usage
python
driver = webdriver.Firefox()
????Pros
- 在真正的瀏覽器中運(yùn)行并支持JavaScript。
- 比Internet Explorer Driver更快。
????Cons
- Slower than the HtmlUnit Driver
????修改Firefox配置文件
假設(shè)您想修改用戶代理字符串(如上所示),但是您已經(jīng)得到了一個包含幾十個有用擴(kuò)展的Firefox配置文件。獲取這個概要文件有兩種方法。假設(shè)該配置文件是使用Firefox的配置文件管理器(Firefox -ProfileManager)創(chuàng)建的:
java
ProfilesIni allProfiles = new ProfilesIni();
FirefoxProfile profile = allProfiles.getProfile("WebDriver");
profile.setPreferences("foo.bar", 23);
WebDriver driver = new FirefoxDriver(profile);
當(dāng)我們在Firefox Driver中開發(fā)特性時,我們就暴露了使用它們的能力。例如,在我們感覺本地事件在Firefox中是穩(wěn)定的Linux,在默認(rèn)情況下它們是禁用的。使他們:
python
profile = webdriver.FirefoxProfile()
profile.native_events_enabled = True
driver = webdriver.Firefox(profile)
????Info
請參閱wiki頁面中的Firefox部分,了解最新的信息。
??Internet Explorer Driver
InternetExplorerDriver是一個獨立的服務(wù)器,它實現(xiàn)了WebDriver的有線協(xié)議。這個驅(qū)動程序已經(jīng)測試了ie7、8、9、10和11,并在Vista、Windows 7、Windows 8和Windows 8.1的適當(dāng)組合上進(jìn)行了測試。截至2014年4月15日,IE 6不再受支持。
驅(qū)動程序支持運(yùn)行32位和64位版本的瀏覽器。如何確定在啟動瀏覽器時使用哪個“bit-ness”取決于IEDriverServer的哪個版本。exe。如果是32位版本的IEDriverServer。exe啟動后,IE的32位版本將啟動。同樣,如果IEDriverServer的64位版本。exe啟動,將啟動64位版本IE。
????Usage
Python
driver = webdriver.Ie()
????Pros(優(yōu)點)
- 在真正的瀏覽器中運(yùn)行并支持Javascript。
????Cons(缺點)
- 很明顯,InternetExplorerDriver只會在Windows上運(yùn)行!
- 比較慢(雖然還是很時髦!)
????Info
查看wiki頁面的Internet Explorer部分 ,了解最新的信息。請?zhí)貏e注意所需的配置部分。
??
??ChromeDriver
ChromeDriver由Chromium項目維護(hù)/支持。WebDriver通過chromedriver二進(jìn)制文件(在chromium項目的下載頁面上找到)與Chrome合作。你需要安裝chromedriver和chrome瀏覽器的版本。chromedriver需要放在系統(tǒng)的路徑上,以便WebDriver自動發(fā)現(xiàn)它。chromedriver在默認(rèn)安裝路徑中發(fā)現(xiàn)了Chrome瀏覽器本身。這些都可以被環(huán)境變量覆蓋。更多信息請參考 the wiki(維基百科)。
????Usage
Python
driver = webdriver.Chrome()
????Pros(優(yōu)點)
在真正的瀏覽器中運(yùn)行并支持JavaScript。
因為Chrome是一個基于webkit的瀏覽器,ChromeDriver可以讓你驗證你的網(wǎng)站在Safari中運(yùn)行。注意,由于Chrome使用的是自己的V8 JavaScript引擎而不是Safari的Nitro引擎,JavaScript的執(zhí)行可能會有所不同。
????Cons(缺點)
- Slower than the HtmlUnit Driver
??
????Info
See our wiki,了解最新的信息。更多信息也可以在 downloads page
找到。
??
????Getting running with ChromeDriver
下載ChromeDriver可執(zhí)行文件,并遵循 wiki page上的其他說明。
??
??Opera Driver
See the Opera Driver wiki article in the Selenium Wiki for information on using the Opera Driver.
??
??iOS Driver
See either the ios-driver or appium projects.
??
??Android Driver
See the Selendroid project
??
Alternative Back-Ends: Mixing WebDriver and RC Technologies
??WebDriver-Backed Selenium-RC
WebDriver的Java版本提供了Selenium-RC API的實現(xiàn)。這意味著您可以使用Selenium-RC API使用底層的WebDriver技術(shù)。這主要是為向后兼容性提供的。它允許使用Selenium-RC API的現(xiàn)有測試套件在覆蓋下使用WebDriver。它提供了幫助簡化遷移到Selenium-WebDriver的路徑。同樣,這允許在相同的測試代碼中同時使用兩個api。
Selenium-WebDriver是這樣使用的:
java
// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();
// A "base url", used by selenium to resolve relative URLs
String baseUrl = "http://www.google.com";
// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
// Perform actions with selenium
selenium.open("http://www.google.com");
selenium.type("name=q", "cheese");
selenium.click("name=btnG");
// Get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();
//Finally, close the browser. Call stop on the WebDriverBackedSelenium instance
//instead of calling driver.quit(). Otherwise, the JVM will continue running after
//the browser has been closed.
selenium.stop();
????優(yōu)點(Pros)
- 允許WebDriver和Selenium api共存。
- 提供從Selenium RC API到WebDriver的管理遷移的簡單機(jī)制。
- 不需要運(yùn)行獨立的Selenium RC服務(wù)器嗎?
????缺點(Cons)
- 不能實現(xiàn)每個方法
- 更高級的Selenium使用(使用“browserbot”或來自Selenium Core的其他內(nèi)置JavaScript方法)可能不起作用。
- 由于底層實現(xiàn)差異,一些方法可能會比較慢。
??Backing WebDriver with Selenium
WebDriver不像Selenium RC那樣支持很多瀏覽器,所以為了在使用WebDriver API時提供支持,您可以使用SeleneseCommandExecutor。
以這種方式支持Safari,并使用以下代碼(確保禁用彈出式阻塞):
java(官方文檔只提供了 JAVA 示例):
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setBrowserName("safari");
CommandExecutor executor = new SeleneseCommandExecutor(new URL("http://localhost:4444/"), new URL("http://www.google.com/"), capabilities);
WebDriver driver = new RemoteWebDriver(executor, capabilities);
目前,這種方法存在一些主要的局限性,尤其是findElements不像預(yù)期的那樣工作。另外,由于我們使用Selenium Core來驅(qū)動瀏覽器,所以您受到JavaScript sandbox的限制。
??
運(yùn)行獨立的Selenium服務(wù)器,用于遠(yuǎn)程驅(qū)動程序(Running Standalone Selenium Server for use with RemoteDrivers)
從Selenium的下載頁面下載selenium-server-standalone-<version>。jar和可選IEDriverServer。如果您計劃使用Chrome,請從 Google Code下載。
打開IEDriverServer和/或chromedriver,并將它們放在$PATH / %PATH%上的目錄中—Selenium服務(wù)器應(yīng)該能夠處理對IE / Chrome的請求,而無需進(jìn)行額外的修改。
在命令行上啟動服務(wù)器
java -jar <path_to>/selenium-server-standalone-<version>.jar
如果您想要使用本機(jī)事件功能,請在命令行上使用該選項指示此功能
-Dwebdriver.enable.native.events=1
對于其他命令行選項,執(zhí)行
java -jar <path_to>/selenium-server-standalone-<version>.jar -help
為了正常運(yùn)行,應(yīng)該允許以下端口進(jìn)入TCP連接:4444、7054-5(或者是您計劃運(yùn)行的并發(fā)實例數(shù)量的兩倍)。在Windows下,您可能還需要打開應(yīng)用程序。
Additional Resources
你可以在 WebDriver’s wiki中找到更多的WebDriver資源。
當(dāng)然,不要猶豫,在任何Selenium主題上進(jìn)行internet搜索,包括Selenium- webdriver的驅(qū)動程序。有很多關(guān)于Selenium的博客,以及許多用戶論壇上的帖子。另外,Selenium User’s Group是一個很好的資源。
http://groups.google.com/group/selenium-users。
Next Steps
這一章簡單地介紹了WebDriver及其一些關(guān)鍵功能。一旦熟悉了Selenium-WebDriver API,您就會想要學(xué)習(xí)如何構(gòu)建可維護(hù)性、可擴(kuò)展性和降低脆弱性的測試套件。大多數(shù)Selenium專家現(xiàn)在建議的方法是使用頁面對象設(shè)計模式(Page Object Design Pattern)和可能的頁面工廠(Page Factory)來設(shè)計測試代碼。通過在Java和c#中提供一個PageFactory類,Selenium-WebDriver提供了支持。在 next chapter中,我們將介紹這一主題,以及其他高級主題。另外,對于該技術(shù)的高級描述,您可能需要查看 Test Design Considerations chapter。這兩章都介紹了通過使測試代碼更模塊化編寫更易于維護(hù)的測試的技術(shù)。
Next topic