标签:
1.元素定位
在本章中,我们将讨论
u 使用浏览器工具来检查页面中元素的结构
u 使用findElement方法定位元素
u 使用findElements方法来定位元素
u 定位链接
u 通过标签名称定位元素
u 使用CSS选择器定位元素
u 使用XPath定位元素
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 |
标签:
原文地址:http://www.cnblogs.com/lincj/p/5507483.html