1.元素定位 javascript
在本章中,咱們將討論css
u 使用瀏覽器工具來檢查頁面中元素的結構html
u 使用findElement方法定位元素java
u 使用findElements方法來定位元素jquery
u 定位連接web
u 經過標籤名稱定位元素ajax
u 使用CSS選擇器定位元素express
u 使用XPath定位元素api
u 使用文本定位元素瀏覽器
u 使用高級CSS選擇器定位元素
u 使用jQuery選擇器
u 定位表格的行和列
u 定位表格中的子元素
1.1.介紹
成功的自動化GUI(圖形用戶界面)測試取決於從被測試的應用程序中識別和定位GUI元素,而後執行操做和驗證這些元素來實現測試流。這能夠歸結爲測試工具備效的識別各類GUI元素的能力。
Selenium WebDriver提供一個先進的技術來定位web頁面元素。Selenium功能豐富的API提供了多個定位策略如:Name、ID、CSS選擇器、XPath等等。咱們也能夠執行自定義的定位策略來定位元素。
在本章中,咱們將探索如何使用定位策略,從簡單的ID,Name和Class開始。
在任何一個Web項目中,給GUI的元素附上屬性如Name,ID或Class是很是好的作法。這使得應用程序更加容易測試符合易訪問性的標準。可是,有時候並非所指望的那樣。遇到這些場景,咱們就須要使用高級的定位策略如CSS選擇器和XPath。
CSS選擇器和XPath在Selenium用戶中很是流行,可是CSS選擇器相比XPath從難易、速度、效率來講更爲推薦你們使用。
1.2.使用瀏覽器工具來檢查頁面元素結構
在咱們開始探測定位器以前,咱們須要先分析一下頁面和元素,瞭解一下他們的結構,元素有哪些屬性,JavaScript或AJAX是怎麼調用的。等等。
瀏覽器爲最終用戶渲染的視覺元素經過隱藏掉HTML代碼和其餘資源。當咱們想要用Selenium WebDriver自動的進行交互的時候,咱們須要仔細查瀏覽器背後渲染頁面和元素的代碼。咱們須要識別出有用的信息如屬性值和元素結構來定位元素,再利用Selenium WebDriver API模擬執行用戶的操做。
這裏有一個BMI體重計算的頁面和HTML代碼,下圖所示
你能夠經過右擊瀏覽器窗口,在彈出的菜單中選擇View Page Source來查看頁面的代碼。代碼將會顯示在一個獨立的窗口中。但這也可能看起來有一點混亂和難以理解。
咱們須要一個特別的工具讓顯示的信息有結構的更易於理解的格式。在這個祕籍中在深刻到定位器以前咱們將會介紹一些這樣的工具。
如何實現如何實現
在下面幾個部分中,咱們將探討一些內置在瀏覽器的工具和插件來分析元素和頁面結構。這些工具將幫助咱們瞭解頁面上的元素和它們的屬性,DOM結構,JavaScript調用,CSS 樣式屬性等等。
利用Firefox的Firebug插件來檢查頁面中的元素
新版本的Firefox提供內置的方法來分析頁面和元素;然而,咱們將使用Firebug插件具備更強大的功能。你須要從 https://addons.mozilla.org/en-us/firefox/addon/ firebug/ 安裝Firebug。
檢查頁面的元素,將鼠標移向所需查看的元素後右鍵鼠標打開彈出菜單。選擇Inspect Element with Firebug選項,以下圖所示:
HTML代碼在Firebug下以樹型結構顯示出來,以下圖所示:
Firebug提供了各類其餘調試特性。它還能夠爲指定元素生成XPath和CSS選擇器。爲此,選擇所需的元素,而後右擊鼠標,選擇Copy XPath或Copy CSS Path選項,以下圖所示
XPath或CSS選擇器的值將會複製剪貼板上。
利用Chrome檢查頁面中的元素
Chrome提供了一個內置的功能來分析頁面和元素。這和firebug很類似。你能夠將鼠標移向所需查看的元素,右擊彈出菜單,而後選擇Inspect Element選項。這將在瀏覽器中打開開發人員工具。顯示信息相似於Firebug,以下圖所示:
Chrome開發工具還提供一個特性,在那裏你能夠獲得一個元素的XPath,右鍵單擊所需的元素,從彈出菜單中選擇Copy XPath。
利用Internet Explorer檢查頁面中的元素
相似於Google Chrome,Microsoft Internet Explorer也提供了一個內置的分析頁面和元素的特性。
按F12鍵打開開發人員工具,以下圖所示
檢查一個元素,單擊指針()圖標,將鼠標懸停在所需查看的元素上。開發工具高亮此元素爲藍色,HTML代碼將以樹型結構顯示,以下圖所示:
如何實現如何實現
瀏覽器開發工具在測試開發的過程中派的上用場。這些工具將幫助你找到定位元素,解析代碼,以樹結構顯示出來。這些工具還提供了樣式的應用、頁面資源,頁面的DOM(文檔對象模型),JavaScript代碼信息等等。
有些工具還能夠運行JavaScript代碼進行測試和調試。
在下面的祕籍中咱們將探索Selenium WebDriver的各類定位器 ,這些工具都將幫助你找到和決定使用哪一種Selenium WebDriver API的定位策略和方法。
1.3.使用findElement方法定位元素
selenium WebDriver定位元素是經過使用findElement()和findElements()方法。
findElement()方法返回一個基於指定查尋條件的WebElement對象或是拋出一個沒有找到符合條件元素的異常。
findElements()方法會返回匹配指定查詢條件的WebElements的集合,若是沒有找到則返回爲空。
查詢方法會將By實例做爲參數傳入。Selenium WebDriver提供了By類來支持各類查詢策略。
下面的表格列出了各類Selenium WebDriver支持的定位策略。
策略 |
語法 |
描述 |
By ID |
Java: driver.findElement(By.id(<element ID>)) |
經過元素ID屬性定位元素 |
|
C#: driver.FindElement(By.Id(<elementID>)) |
|
|
Python: driver.find_element_by_id(<elementID>) |
|
|
Ruby: driver.find_element(:id,<elementID>) |
|
By Name |
Java: driver.findElement(By.name(<element name>)) |
經過元素Name屬性定位元素 |
|
C#: driver.FindElement(By.Name(<element name>)) |
|
|
Python: driver.find_element_by_name(<element name>) |
|
|
Ruby: driver.find_element(:name,<element name>) |
|
By class name |
Java:driver.findElement(By.className(<element class>)) |
經過元素class name屬性定位元素 |
|
C#: driver.FindElement(By.ClassName(<elementclass>)) |
|
|
Python: driver.find_element_by_class_name(<elementclass>) |
|
|
Ruby: driver.find_element(:class,<element class>) |
|
By tag name |
Java: driver.findElement(By.tagName(<htmltagname>)) |
經過HTML標記名定位元素 |
|
C#: driver.FindElement(By.TagName(<htmltagname>)) |
|
|
Python: driver.find_element_by_tag_name(<htmltagname>) |
|
|
Ruby: driver.find_element(:tag_name,<htmltagname> |
|
By link text |
Java: driver.findElement(By.linkText(<linktext>)) |
經過文本定位連接 |
|
C#: driver.FindElement(By.LinkText(<linktext >)) |
|
|
Python: driver.find_element_by_link_text(<linktext >) |
|
|
Ruby: driver.find_element(:link_text,< linktext >) |
|
By partial link text |
Java: driver.findElement(By.partialLinkText(<linktext>)) |
經過部分文本定位連接 |
|
C#: driver.FindElement(By.PartialLinkText(<linktext >)) |
|
|
Python: driver.find_element_by_partial_link_text(<linktext >) |
|
|
Ruby: driver.find_element(:partial_link_text,<linktext >) |
|
By CSS |
Java: driver.findElement(By.cssSelector(<css selector>)) |
經過CSS定位元素 |
|
C#: driver.FindElement(By.CssSelector(<cssselector >)) |
|
|
Python: driver.find_elements_by_css_selector (<css selector>) |
|
|
Ruby: driver.find_element(:css,< css selector >) |
|
By XPath |
Java: driver.findElement(By.xpath(<xpath query expression>)) |
經過XPath定位元素 |
|
C#: driver.FindElement(By.XPath(<xpath query expression>)) |
|
|
Python: driver.find_elements_by_xpath (<xpath query expression>) |
|
|
Ruby: driver.find_element(:xpath,<xpath query expression>) |
|
在這個祕籍中,咱們將使用findElement()方法來定位元素。
如何實現如何實現
使用id,name或class屬性是定位元素的首選方法。讓咱們試試用上面描述的這些方法來定位元素
經過ID屬性來查找元素
用元素的id是最首選的方法來定位頁面元素。W3C的標準中推薦開發人員爲每個元素都提供一個獨一無二的id屬性。擁有id屬性,就能夠提供一個明確可靠的方法來定位頁面上的元素。
當處理DOM的時候,瀏覽器使用id做爲首選識別元素的方法,同時這也是最快速的策略。
如今咱們看看如何在一個登陸表單中使用id屬性來定位元素。
<form name="loginForm">
<label for="username">UserName: </label> <input type="text"
id="username" /><br/>
<label for="password">Password: </label> <input
type="password" id="password" /><br/>
<input name="login" type="submit" value="Login" />
</form>
爲定位User Name和Password字段,咱們能夠經過下面方法使用id屬性來定位元素:
WebElement username = driver.findElement(By.id("username"));
WebElement password = driver.findElement(By.id("password"));
經過Name屬性來查找元素
使用元素的id屬性來定位是最爲推薦的方法,可是你也可能會由於下列緣由不能使用id屬性:
l 不是全部的頁面上元素都會指定id屬性
l id屬性的值是動態生成的
在下面的例子中,登陸表單使用了name屬性而不是id屬性
<form name="loginForm">
<label for="username">UserName: </label> <input type="text"
name="username" /><br/>
<label for="password">Password: </label> <input
type="password" name="password" /><br/>
<input name="login" type="submit" value="Login" />
</form>
咱們可使用經過下面的方法使用name屬性來定位元素:
WebElement username = driver.findElement(By.name("username"));
WebElement password = driver.findElement(By.name("password"));
和id不一樣,name屬性未必是頁面上惟一的屬性。你可能會找到多個具備相同name屬性的元素,在這樣的狀況下,頁面上的第一個出現的元素將會被選擇,可是個元素未必是你想尋找的,這將會致使測試失敗。
經過CSS屬性來查找元素
除了使用id和name屬性,你還可使用class屬性來定位元素。class屬性是用來指定元素所應用的CSS樣式。
在這個例子中,表單元素使用了class屬性而不是id屬性:
<form name="loginForm">
<label for="username">UserName: </label> <input type="text"
class="username" /></br>
<label for="password">Password: </label> <input
type="password" class="password" /></br>
<input name="login" type="submit" value="Login" />
</form>
咱們可使用經過下面的方法使用class屬性來定位元素
WebElement username =
driver.findElement(By.className("username"));
WebElement password =
driver.findElement(By.className("password"));
如何實現如何實現
Selenium WebDriver 提供了findElement()方法來定位頁面中須要測試的元素。
當開始尋找符合指定條件的元素時,它將會查詢整個DOM,而後返回第一個找到的匹配的元素。
更多說明 更多說明
WebElement類也能夠支持查詢子類元素。例如,假設頁面上有一些重複的元素。可是,他們在不一樣的<div>中。咱們第一步能夠先定位到其父元素<div>而後在定位其子元素,方法以下:
WebElement div = driver.findElement(By.id("div1"));
WebElement topLink = div.findElement(By.linkText("top"));
你也能夠將他們縮寫成一行:
WebElement topLink = driver.findElement
(By.id("div1")).findElement(By.linkText("top"));
NoSuchElementFoundException
findElement()和findElements()方法當找不到相應的元素的時候就會拋出NoSuchElementFoundException異常。
1.4.使用findElements方法定位元素
Selenium WebDriver提供了findElements()方法,能夠獲得匹配指定規則的集合。當咱們須要在一組類似的元素上操做的時候,這個方法會是很是有用的。例如,咱們能夠獲得頁面上全部的連接或是表格中全部的行等等。
在這個祕籍中,咱們將用findElements()方法獲得全部的連接並打印他們的目標超連接。
如何實現如何實現
測試需求以百度首頁爲例,咱們要驗證百度首頁導航連接的數量,並打印出他們的超連接地址
package com.example.tests; import static org.junit.Assert.*; import java.util.*; import org.junit.*; import org.openqa.selenium.*; import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 { @Test public void test() { WebDriver driver = new InternetExplorerDriver(); driver.get("http://www.baidu.com"); List<WebElement> links = driver.findElements(By.cssSelector("#nv a")); //驗證連接數量 assertEquals(10, links.size()); //打印href屬性 for (int i = 0; i < links.size(); i++) { System.out.println(links.get(i).getAttribute("href")); } driver.close(); } } |
執行後打印的結果爲
http://news.baidu.com/
http://tieba.baidu.com/
http://zhidao.baidu.com/
http://music.baidu.com/
http://image.baidu.com/
http://video.baidu.com/
http://map.baidu.com/
http://baike.baidu.com/
http://wenku.baidu.com/
http://www.baidu.com/more/
findElements()方法返回全部匹配定位策略的WebElement的集合,咱們可使用java中List類來建立WebElements的實例
List類中的size()方法會告訴你這個集合中元素的總數量。
經過for循環將獲得List中的全部的元素,再調用getAttribute()方法獲得元素的屬性。
1.5.定位連接
Selenium WebDriver提供了多種定位連接的方法。你能夠經過連接的名稱和部分名稱來定位一個連接。
當連接名是動態變化的時候,使用部分匹配就變得很方便。在這個祕籍中,咱們將看如何使用這些方法來定位頁面中的連接。
如何實現如何實現
讓咱們舉個例子來看看如何使用Selenium WebDriver來定位連接。
經過連接名來定位連接
Selenium WebDriver的By類中提供了linkTest()方法來定位連接。在下面的例子中,咱們將定位Gmail的連接:
WebElement gmailLink = driver.findElement(By.linkText("GMail"));
assertEquals("http://mail.google.com/",gmailLink.getAttribute("href"));
經過部分連接名稱定位連接
Selenium WebDriver的By類也提供了使用部分連接名來定位連接。當開發人員創建了動態的連接名時這種方法就很是的有用。在這個例子中,有一個連接是用來打開收件箱。這個連接同時也會動態的顯示收件箱的數量因此他是在動態變化的過程當中。這裏咱們就可使用partiaLinkTest()來定位固定的或已知不變的一部份名稱,在這個例子中就是「inbox」。
WebElement inboxLink =
driver.findElement(By.partialLinkText("Inbox"));
System.out.println(inboxLink.getText());
若是開發人員提供了id,name或是class屬性,仍是儘可能使用這些方法來定位。
1.6.使用標籤名稱定位元素
Selenium WebDriver的By類中提供了tagName()方法來定位HTML標記名稱。這和getElementByTagName()很類似。
使用標籤名稱能夠很方便地定位元素。例如,定位全部的表格中的<tr>等等。
在這個祕籍中,咱們將學習如何使用tagName來定位元素。
如何實現如何實現
咱們假設你的頁面中只有一個按鈕。你可使用他的標籤來定位此按鈕,方法以下:
WebElement loginButton =
driver.findElement(By.tagName("button"));
loginButton.click();
另外一個例子若是你想統計<table>中有多少行,你能夠這樣來作:
WebElement table = driver.findElement(By.id("summaryTable"));
List<WebElement> rows = table.findElements(By.tagName("tr"));
assertEquals(10, rows.size());
tagName方法查詢DOM,而後返回全部匹配條件的元素。當定位單獨的一個元素時,這種方法是不可靠的,頁面上可能有不少相同的元素。
1.7.使用CSS選擇器定位元素
Cascading Style Sheets ( CSS )是一種樣式風格語言用來描述元素的外觀和格式。
主流的瀏覽器實現CSS解析引擎使用CSS語法來格式化和樣式化頁面。CSS的引進是爲了讓頁面信息和樣式信息能夠分開。更多的CSS信息和CSS選擇器請訪問 http://en.wikipedia.org/wiki/Cascading_Style_Sheets .
Selenium WebDriver使用一樣的CSS選擇器的原則來定位DOM裏的元素。這是一個相對XPath更可靠更快速的方式來定位複雜的元素。
在這個祕籍中,咱們將探索一些基本的CSS選擇器,後面咱們會逐步深刻到更高級的用法。
如何實現如何實現
讓咱們探索一些基本的CSS選擇器。Selenium WebDriver的By類提供了cssSelector()方法,讓咱們可使用CSS選擇器來定位元素。
使用絕對路徑來定位元素
CSS絕對路徑指的是在DOM結構中具體的位置。下面一個例,使用絕對路徑來定位用戶名輸入字段。在使用絕對路徑的時候,每一個元素之間要有一個空格。
WebElement userName = driver.findElement(By.cssSelector("html body div div form input"));
你也能夠以父子關係的方式」>」來描述這個選擇器
WebElement userName = driver.findElement(By.cssSelector("html >
body > div > div > form > input"));
可是,這個策略會有一些的限制,他取決於頁面的整個結構。若是有些許改變,選擇器將找不到這個元素。
使用相對路徑來定位元素
使用相對路徑的時候咱們能夠直接定位元素。不用考慮他在DOM中的位置。例如,咱們能夠用這樣的方法來定位用戶輸入字段,假設他在DOM中是第一個<input>元素:
WebElement userName = driver.findElement(By.cssSelector("input"));
使用相對路徑來定位元素
當咱們使用CSS選擇器來查找元素的時候,咱們可使用class屬性來定位元素。咱們能夠先指定一個HTML的標籤,而後加一個「.」符號,跟上class屬性的值,方法以下:
WebElement loginButton =
driver.findElement(By.cssSelector("input.login"));
這一樣能夠找到按鈕的<input>標籤class爲login的元素。
你還能夠簡寫查詢表達示,只用 .和class屬性值,省略掉HTML的標籤。可是,這將會返回全部class爲login的元素,致使結果並不必定是你所指望的那樣。
WebElement loginButton = driver.findElement(By.cssSelector(".login"));
此方法和className()很類似。
使用相對ID選擇器來定位元素
咱們也可使用元素的ID來定位。先指定一個HTML標籤,而後加上一個「#」符號,跟上id的屬性值,以下所示:
WebElement userName =
driver.findElement(By.cssSelector("input#username"));
這將會返回input標籤中id爲username的元素。
你能夠經過這樣來簡化一下表達式,輸入「#」符號,跟上id的名稱便可,省略到HTML的標籤。可是,這也將會返回全部id爲username的元素,結果未必是你所指望。用的時候要很是當心。
WebElement userName =
driver.findElement(By.cssSelector("#username"));
這個方法和id選擇器策略很像。
使用屬性來定位元素
除了class和id屬性,CSS選擇器也可使用其餘的元素屬性來定位。下面的例子中,將使用<input>中的Name屬性。
WebElement userName =
driver.findElement(By.cssSelector("input[name=username]"));
使用name屬性來定位元素和直接用By類中的name()方法來定位很類似。
讓咱們試試使用其餘的屬性,下面的例子中,命名alt屬性來定位<img>元素。
WebElement previousButton =
driver.findElement(By.cssSelector("img[alt='Previous']"));
你能夠會遇到一個屬性不足以來定位到一個元素的狀況,你須要聯合使用其餘的屬性來達到精確匹配。下面的例子中,使用多個屬性來定位<input>元素。
WebElement previousButton = driver.findElement(By.cssSelector("input[type='submit'][value='Login']"));
使用屬性名稱選擇器來定位元素
這個策略和以前的有些不一樣,咱們只經過指定元素中屬性的名稱而不是屬性的值來定位元素。例如,咱們想要查找全部<img>標籤中,含有alt屬性的元素。
List<WebElement> imagesWithAlt =
driver.findElements(By.cssSelector("img[alt]"));
not()僞類也可使用來匹配不知足規則的元素。例如,想要定位那些<img>標籤中不含有alt屬性,方法以下:
List<WebElement> imagesWithoutAlt =
driver.findElements(By.cssSelector("img:not([alt])"));
部分屬性值的匹配
CSS選擇器提供了一個部分屬性值匹配定位元素的方法。這爲了測試那些頁面上具備動態變化的屬性的元素是很是有用的。例如,在ASP.NET應用中,元素id是動態生成的。下面的表格介紹瞭如何使用部分匹配的語法:
語法 |
例子 |
描述 |
^= |
Input[id^= ' ctrl'] |
以XXX開始 例如,若是一個元素的ID是ctrl_12,就能夠定位到此元素,匹配到id的頭部ctrl。 |
$= |
input[id$='_userName'] |
以XXX結尾 例如,若是一個元素的ID是a_1_userName,這將會匹配到id的尾部_userName。 |
*= |
Input[id*='userName'] |
包含 例如,若是一個元素的ID是panel_ login_userName_textfield,這將會匹配到此id值的_userName,從而定位到元素。 |
CSS選擇器是CSS匹配HTML或XML一系元素中的規則中的一個模式和部分。
主流的瀏覽器都支持對CSS的解析,應用到相應的元素上去。Selenium WebDriver使用CSS解析引擎來定位頁面上的元素。CSS選擇器提供多樣的方法,規則和模式來定位頁面上的元素。這也是相對咱們後面說的XPath更加穩定和快速的方法。
使用CSS選擇器,能夠經過多樣的方法來定位元素如Class,ID,屬性值和在此祕籍中咱們描述的一些文本內容方法。
1.8.使用XPath定位元素
XPath是XML路徑語言,用來查詢XML文檔裏中的節點。主流的瀏覽器都支持Xpath,由於HTML頁面在DOM中表示爲XHTML文檔。
Xpath語言是基於XML文檔的樹結構,並提供了瀏覽樹的能力,經過多樣的標準來選擇結點。
Selenium WebDriver支持使用Xpath表達式來定位元素。
利用Xpath來定位元素很是方便,可是,便捷的定位策略犧牲了系統的性能。
XPath和CSS中最重要的區別在於,Xpath能夠向前和向後查詢DOM結構的元素,而CSS只能向前查詢。這意味着使用XPath能夠經過子元來定位父元素。
在這個祕籍中,咱們將探索一些基本的XPath查詢來定位元素而後再學習一些XPath的高級應用。
如何實現如何實現
讓咱們探索一些Selenium WebDriver中基本的XPath表達式。Selenium WebDriver提供了Xpath()方法來定位元素。
經過絕對路徑定位元素
和CSS絕對路徑類似,XPath絕對路徑適用於指定元素的位置。這裏的一個例子就是使用絕對路徑來定位用戶名的字段。在每個元素之間須要有一個空格。
WebElement userName =
driver.findElement(By.xpath("html/body/div/div/form/input"));
可是,這個策略有侷限性,他須要參考整個頁面的文檔結構。如改變了,此元素的定位將會失敗。
經過相對路徑定位元素
用相對路徑,咱們能夠直接找到元素而無論其在DOM中的位置。例如,咱們能夠經過以下方法來定位用戶名字段,假設這個<input>元素處於DOM中第一個:
WebElement userName = driver.findElement(By.xpath("//input"));
使用索引來定位元素
在前面的示例中,XPath查詢將返回第一個DOM中<input>元素。可能會有多個元素都匹配了XPath查詢。若是元素不是第一個元素,咱們也能夠指定他的個數來找到它。例如在咱們的登陸表單,咱們能夠找到密碼字段 - 第二個<input>,方法以下:
WebElement passwd = driver.findElement(By.xpath("//input[2]"));
使用XPath及屬性值定位元素
和CSS類似,咱們能夠在XPath中使用元素的屬性來定位元素。在下面的例子中,可使用ID屬性來定位用戶名字段。
WebElement userName =
driver.findElement(By.xpath("//input[@id='username']"));
另外一個使用alt屬性來定位image屬性的例子:
WebElement previousButton =
driver.findElement(By.xpath("img[@alt='Previous']"));
你能夠會遇到一個屬性不足以來定位到一個元素的狀況,你須要聯合使用其餘的屬性來達到精確匹配。下面的例子中,使用多個屬性來定位<input>元素。
WebElement previousButton =
driver.findElement(By.xpath
("//input[@type='submit'][@value='Login']"));
使用XPath和and操做符也一樣能夠達到相同的效果
WebElement previousButton = driver.findElement
(By.xpath("//input[@type='submit'and @value='Login']"));
下面的例子中,使用or操做符任何一個屬性知足也將能夠對元素進行定位
WebElement previousButton = driver.findElement
(By.xpath("//input[@type='submit'or @value='Login']"));
使用XPath及屬性名稱定位元素
這個策略和以前的有些不一樣,咱們只經過指定元素中屬性的名稱而不是屬性的值來定位元素。例如,咱們想要查找全部<img>標籤中,含有alt屬性的元素。
List<WebElement> imagesWithAlt = driver.findElements
(By.xpath ("img[@alt]"));
部分屬性值的匹配
相似於CSS選擇器,XPath還提供了一種一些方法部分匹配屬性來定位元素。這對於網頁中的屬性是動態變化的時候是很是有用的。例如,ASP.NET應用程序中動態生成id屬性值。下面的表說明了使用這些XPath功能:
語法 |
例子 |
描述 |
starts-with() |
input[starts-with(@id,'ctrl')] |
例如,若是元素的ID爲ctrl_12,將會匹配以ctrl開始的屬性值。 |
ends-with() |
input[ends-with(@id,'_userName')] |
例如,若是元素的ID爲a_1_userName,將會匹配以userName結尾的屬性值。 |
contains() |
Input[contains(@id,'userName')] |
例如,若是元素的ID爲panel_login_userName_textfield,將會匹配含有userName屬性值。 |
使用值來匹配任意屬性及元素
XPath能夠匹配任意元素屬性中指定的值。例如,在下面的XPath查詢中,「userName」是指定的。XPath將會檢查全部元素中是否有屬性等於」userName」,並將其返回。
WebElement userName =
driver.findElement(By.xpath("//input[@*='username']"));
使用XPath軸來定位元素
XPath軸是藉助於文檔中元素與元素之間的關係來定位。下面有一個簡單的<table>的XPath軸的例子。
下面是用圖形來表示HTML元素間的關係
軸 |
描述 |
例子 |
結果 |
ancestor |
選擇當前節結點全部的父類元素,包括祖先元素 |
//td[text()='Product 1']/ancestor::table |
獲得table元素 |
descendant |
選擇當前節點全部子元素 |
//table/ descendant::td/input |
獲得第三例第二行的input元素 |
following |
選擇當前元素結束標籤後的全部元素 |
//td[text()='Product 1']/following::tr |
獲得第到第二行的tr元素 |
following- sibling |
選擇當前元素後的兄弟元素 |
//td[text()='Product 1']/following- sibling::td |
獲得第二行第二列的td元素 |
preceding |
選取文檔中當前節點的開始標籤以前的全部節點 |
//td[text()='$150']/ preceding::tr |
獲得第一行tr |
preceding- sibling |
選取當前節點以前的全部同級節點。 |
//td[text()='$150']/ preceding-sibling::td |
獲得第三行第一列的td |
更多關於XPath軸請訪問http://www.w3schools.com/xpath/xpath_axes.asp 。
Xpath是處理、查詢瀏覽器DOM強大的語言,能夠瀏覽DOM中的元素和屬性。XPath也提供了一些規則、函數和語法來定位元素。
主流的瀏覽器都支持XPath,Selenium WebDriver也提供了經過XPath來定位元素的能力。
使用By類中的Xpath()方法能夠定位元素。XPath的查詢是慢於CSS選擇器,由於XPath支持雙向的查詢。你能夠經過元素的父,兄弟,子節點來定位元素。
1.9.使用文本元素
當你測試網頁應用的時候,你也可能遇到開發人員沒有分配任何屬性給元素,這時候定位元素就會變得很困難。
使用CSS選擇器或XPath,咱們可使用他的本文內容來定位元素。在這個祕籍中,咱們將探索如何使用文本值來定位元素。
如何實現如何實現
使用文原本定位元素,CSS選擇器和XPath提供了方法來經過文本定位元素。若是一個元素包含一個指定的文本,將會返回到測試。
使用CSS選擇器僞類定位元素
CSS選擇器提供了contains()僞類來經過指定文本定位元素。例如,你能夠經過表格裏的內容來定位單元格,方法以下:
WebElement cell =
driver.findElement(By.cssSelector("td:contains('Item 1')"));
contains()僞類接受一個被查詢的文本做爲參數。而後查詢全部<td>標籤裏包含指定文本的元素。(注:contains()方法已經被CSS3棄用了)
以百度首頁爲例,如今我想定位新聞連接
WebElement news =
driver.findElement(By.cssSelector("a:contains('新')"));
做爲contains()的替代,你可使用innerText屬性(不支持Firefox)或textContent屬性(支持Firefox),方法以下:
WebElement news =
driver.findElement(By.cssSelector("a[innerText='新聞']"));
或
WebElement news = driver.findElement
(By.cssSelector("a[textContent='新聞']"));
使用XPath的text函數
XPath提供了text()方法來定位指定文本的元素,方法以下:
WebElement cell = driver.findElement
(By.xpath("//td[contains(text(),'Item 1')]"));
這裏contains()與text()函數一塊兒使用。text()函數,返回完整的文本,contains()函數將檢查是否包含此文本。
使用XPath精確文本定位元素
利用XPath,經過精確的文原本定位元素,方法以下:
WebElement cell = driver.findElement
(By.xpath("//td[.='Item 1']"));
CSS選擇器和XPath提供基於元素文本內容方法來定位元素。這種當元素沒有足夠的屬性或當沒有其餘策略時會很方便找到這些元素。
對於使用文本定位,不管是CSS選擇器仍是XPath都是搜索整個DOM,返回匹配的元素。
1.10.使用高級的CSS選擇器定位元素
咱們在以前學習了一些基本的CSS選擇器,在此祕籍中,咱們將探索用一些高級的CSS選擇器來定位元素
如何實現如何實現
在1.7章節中,咱們已經探索了一些基本的CSS選擇器,讓咱們探索一些高級的CSS選擇器,如相鄰的兄弟結合僞類的使用。
查詢子元素
CSS選擇器提供了多種方法經過父元素來定位它的子元素。仍是以前的例子
<form name="loginForm">
<label for="username">UserName: </label> <input type="text"
class="username" /></br>
<label for="password">Password: </label> <input
type="password" class="password" /></br>
<input name="login" type="submit" value="Login" />
</form>
若是想定位表單中的用戶名輸入框,咱們使用在其父子元素間使用「>」符號。
WebElement userName = driver.findElement
(By.cssSelector("form#loginForm > input"));
類似的使用nth-child()方法也能夠定位成功,方法以下:
WebElement userName = driver.findElement
(By.cssSelector("form#loginForm :nth-child(2)"));
下列表格列出了使用僞類來定位子元素的例子:
僞類 |
例子 |
描述 |
:first-child |
form#loginForm :first-child |
定位表單裏第一個子元素username標籤 |
:last-child |
form#loginForm :last-child |
定位表單最後一個子元素Login按鈕 |
:nth-child(2) |
form#loginForm :nth-child(2) |
定位表單中第二個子元素username的輸入框 |
查詢兄弟元素
利用CSS選擇器,咱們可使用「+」操做符來定位兄弟元素。仍是以百度首頁爲例
,可使用下例方法來定位百度導航中的「網頁」超連接
WebElement web =
driver.findElement(By.cssSelector("#nv a + b"));
#nv a定位到「新聞」連接,「+ b「後就找到其兄弟<b>元素
使用用戶操做僞類
使用用戶的操做行爲:focus僞類,定位焦點在input框中的元素,方法以下:
WebElement productDescription =
driver.findElement(By.cssSelector("input:focus"));
你也可使:hover和:active僞類來定位元素
使用UI狀態僞類
使用UI狀態僞類,咱們能夠經過元素的各類狀態來定位,如enabled,disable,checked。 下例表格給予了詳細的說明
僞類 |
例子 |
描述 |
:enabled |
input:enabled |
定位全部屬性爲enable的input的元素 |
:disabled |
input:disabled |
定位全部屬性爲disabled的input的元素 |
:checked |
input:checked |
定位全部多選框屬性爲checked的元素 |
訪問 http://www.w3schools.com/cssref/css_selectors.asp 查詢更多CSS選擇器的用法
1.11.使用jQuery選擇器
jQuery選擇器是jQuery庫中很是重要的功能。jQuery選擇器是基於CSS1-3選擇器,加上一些額外的選擇器。這些選擇器和CSS選擇器的使用方法很類似,容許開發人員簡單快速的識別頁面上的元素。一樣能夠定位HTML中的元素做爲一個單獨的元素或是一個元素集合。
jQuery選擇器可使用在那些不支持CSS選擇器的瀏覽器上。
在這個祕籍中,咱們將簡單的探索如何在Selenium WebDriver中使用jQuery選擇器
如何實現如何實現
以jQuery官網爲例,網站自己已經自動加載了jQuery的庫,因此咱們能夠在腳本中直接使用jQuery語法。下面的例子中咱們想使用jQuery的選擇器:even選出右側導航欄中偶數(第一位是索引是0)超連接Download、Blog、Browser Support
package com.example.tests; import static org.junit.Assert.*; import java.util.*; import org.junit.*; import org.openqa.selenium.*; import org.openqa.selenium.ie.InternetExplorerDriver; public class Selenium2 { WebDriver driver = new InternetExplorerDriver(); JavascriptExecutor jse = (JavascriptExecutor)driver; @Test public void jQueryTest() { driver.get("http://www.jquery.com/"); |
List<WebElement> elements = (List<WebElement>)jse.executeScript ("return jQuery.find" + "('.menu-item a:even')"); assertEquals(3,elements.size()); assertEquals("Download",elements.get(0).getText()); assertEquals("Blog",elements.get(1).getText()); assertEquals("Browser Support",elements.get(2).getText()); driver.close(); } } |
Selenium WebDriver使用jQuery API加強了jQuery選擇器,可是,咱們須要確認頁面以經加載了jQuery。jQuery API提供了find()方法來查詢元素。咱們須要使用JavaScriptExecutor類來執行jQuery的find()方法。
find()方法返回了符合查詢條件的元素集合。更多jQuery選擇器信息請查詢 http://api.jquery.com/category/selectors/ 。
在使用jQuery選擇器的時候,有的頁面並未加載jQuery庫,這時候你能夠在加載頁面的時候注入jQuery庫,方法以下:
private void injectjQueryIfNeeded() {
if (!jQueryLoaded())
injectjQuery();
}
public Boolean jQueryLoaded() {
Boolean loaded;
try {
loaded = (Boolean) driver.executeScript("return
jQuery()!=null");
} catch (WebDriverException e) {
loaded = false;
}
return loaded;
}
public void injectjQuery() {
//在head中拼出加載jquery的html
driver.executeScript(" var headID =
document.getElementsByTagName(\"head\")[0];"
+ "var newScript = document.createElement('script');"
+ "newScript.type = 'text/javascript';"
+ "newScript.src = 'http://ajax.googleapis.com/
ajax/libs/jquery/1.7.2/jquery.min.js';"
+ "headID.appendChild(newScript);");
}
仍是以百度首頁爲例,百度首頁沒有jQuery庫。咱們想定位百度導航欄上面的全部超連接元素,並輸出結果。
package com.example.tests; import static org.junit.Assert.*; import java.util.*; import org.junit.*; import org.openqa.selenium.*; import org.openqa.selenium.ie.InternetExplorerDriver; public class Selenium2 { WebDriver driver = new InternetExplorerDriver(); JavascriptExecutor jse = (JavascriptExecutor)driver; @Test public void jQueryTest() { driver.get("http://www.baidu.com/"); injectjQueryIfNeeded(); List<WebElement> elements = (List<WebElement>)jse.executeScript ("return jQuery.find('#nv a')"); assertEquals(7,elements.size()); //驗證超連接的數量 for (int i = 0; i < elements.size(); i++) { System.out.print(elements.get(i).getText() + "、"); } driver.close(); }
private void injectjQueryIfNeeded() { if (!jQueryLoaded()) injectjQuery(); } //判斷是已加載jQuery public Boolean jQueryLoaded() { Boolean loaded; try { loaded = (Boolean)jse.executeScript("return " + |
"jQuery()!=null"); } catch (WebDriverException e) { loaded = false; } return loaded; } //經過注入jQuery public void injectjQuery() { jse.executeScript(" var headID = " +"document.getElementsByTagName(\"head\")[0];" + "var newScript = document.createElement('script');" + "newScript.type = 'text/javascript';" + "newScript.src = " +"'http://ajax.googleapis.com/ajax/" +"libs/jquery/1.7.2/jquery.min.js';" + "headID.appendChild(newScript);"); } } |
injectjQueryIfNeeded()方法首先經過jQueryLoaded()方法來判斷網頁中是否加有jQuery對象。若是沒有,再調用injectjQuery()方法經過增長一個<Script>元素來實時加載jQuery庫,參考的是Google在線庫,你能夠修改例子中的版本,使用最新的jQuery版本。
1.12.定位表格行和單元格
在處理表格時,咱們能夠經過By類中的一些方法快速有效的來定位表格的行和單元格。
在這個祕籍中,咱們將學習如何定位表格中的行和列。
如何實現如何實現
讓咱們建立一個簡單的測試來打印表格中的數據,經過下面的方法來定位表格的行和列:
以W3C School的網頁爲例 http://www.w3school.com.cn/html/html_tables.asp 咱們的需求是先判斷一下這個表格是多少行,而後纔將每個單元格的數據打印出來。
package com.example.tests; import static org.junit.Assert.*; import java.util.*; import org.junit.*; import org.openqa.selenium.*; import org.openqa.selenium.ie.InternetExplorerDriver; public class Selenium2 { WebDriver driver = new InternetExplorerDriver(); JavascriptExecutor jse = (JavascriptExecutor)driver; @Test public void tableTest() { driver.get ("http://www.w3school.com.cn/html/html_tables.asp"); //首先獲得全部tr的集合 List<WebElement> rows = driver.findElements(By.cssSelector(".dataintable tr")); //驗證表格的行數 assertEquals(11,rows.size()); //打印出全部單元格的數據 for (WebElement row : rows) { //獲得當前tr裏td的集合 List<WebElement> cols = row.findElements(By.tagName("td")); for (WebElement col : cols) { System.out.print(col.getText());//獲得td裏的文本 } System.out.println(); } driver.close(); } |
} |
1.13.定位表格中的子元素
對於簡單的表格處理還相對容易些。可是,你可能會遇到相對複雜的表格,表格單元格中還有子元素要和用戶進行交互。例如,在一個電子商務網的購物車頁面,表格中內嵌了不少複雜的元素。
此外,這些元素是基於用戶操做動態生成的。定位這些元素是一個比較有挑戰的任何。
在此祕籍中,咱們將探索使用CSS和XPath定位表格的子元素。
如何實現如何實現
這裏有一個表格的例子,列出了系統用戶和各自的權限。咱們要建立一個測試選擇相應的多選框並檢查選擇的東西是否授予給了用戶。
數據中每一行代碼以下:
<tr>
<td>Nash</td>
<td><a href="mailto:nash@test.com">Nash@test.com</a></td>
<td>
<div>
<label for="user128_admin">Admin</label>
<input type="checkbox" id="user128_admin"
checked="true"/>
<label for="user128_cm">Content Manager</label>
<input type="checkbox" id="user128_cm"/>
<label for="user128_browser">Browser</label>
<input type="checkbox" id="user128_browser"/>
</div>
</td>
</tr>
多選框中的ID是動態的不能和用戶關聯,可是咱們處理這樣的問題可使用CSS選擇器和XPath。在這個例子中,咱們想要給nash用戶授予admin的權限。這可能經過CSS選擇器來實現,方法以下:
WebElement adminCheckBox = driver.findElement
(By.cssSelector("td:contains('Nash')+td+td>div>label:contains
('Admin')+input"));
adminCheckBox.click();
咱們也可使用XPath來實現:
WebElement adminCheckBox = driver.findElement
(By.xpath("//td[contains(text(),'Nash')]/following-
sibling::td/descendant::div/label
[contains(text(),'Admin')]/following-sibling::input"));
adminCheckBox.click();
父,子,兄弟元素,使用CSS或是XPath方法將對於關聯用戶設計出通用的定位策略有很是大的幫助。簡言之,這個策略就是基於元素與元素之間的關係進行定位。
回到咱們的問題,首先咱們須要找到一個惟一方法來識別表中的用戶。爲此,咱們可使用單元格中的用戶名來定位,方法以下:
CSS |
XPath |
td:contains('Nash') |
//td[contains(text(),'Nash')] |
下一步,咱們須要找到子元素的單元格,對於用戶名來講是後面的第2個單元格
CSS |
XPath |
td:contains('Nash')+td+td |
//td[contains(text(),'Nash')]/ following-sibling::td/descendant::div |
下一步,就要定位到正確的多選框
CSS |
XPath |
td:contains('Nash')+td+td>div>label:contains('Admin')+input |
//td[contains(text(),'Nash')]/ following-sibling::td/descendant::div/label[contains(text(),'Admin')]/following-sibling::input |