Selenium 2.0最主要的新特性就是集成了WebDriver API。咱们设计WebDriver的初衷是提供更加简单明了的接口来弥补Selenium-RC API的不足。在动态网页中,一般只会更新局部的html元素,WebDriver会很好的帮助用户快速定位这些元素。咱们最终的目的是经过提供精心设计的面向对象API来解决现代高级网页中的测试难题。javascript
不一样类型的浏览器都会有原生的接口支持自动化操做,Selenium经过这些接口直接向浏览器发送指令。如何发送这些指令取决于你当前使用的浏览器类型,咱们将在这一章节后面来详细介绍。css
看上去WebDriver与以前Selenium-RC的实现方式相似,实际上二者之间存在着本质的区别。对于全部类型的浏览器Selenium-RC都是使用的同一种方法:当浏览器启动时,向其中注入javascript,从而使用这些js来驱动浏览器中的AUT(Application Under Test)。WebDriver并无使用这种技术,它是经过调用浏览器原生的自动化API直接驱动浏览器。html
是否须要是用Selenium Server取决于你使用WebDriver的方式。如下两种状况不须要使用Selenium Server,WebDriver直接运行浏览器便可:一、testcases仅仅使用了Webdriver的API;二、浏览器和testcase在同一台PC上,并且testcases仅仅使用了Webdriver的API。前端
如下三种状况你须要结合Selenium Server来使用WebDriver:java
1)使用Selenium-Grid管理集群环境(或者虚拟机)上的testcase;python
2)须要调用非本机上的不一样版本的浏览器;web
3)未使用任何language binding(java/c#/python/ruby),且有意向使用HtmlUnitDriver。apache
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>MySel20Proj</groupId> <artifactId>MySel20Proj</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.38.0</version> </dependency> <dependency> <groupId>com.opera</groupId> <artifactId>operadriver</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.opera</groupId> <artifactId>operadriver</artifactId> <version>1.5</version> <exclusions> <exclusion> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-remote-driver</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement> </project>请确认你使用的WebDriver是最新的当前版本。在这篇文档撰写时,上述示例给出的是最新的版本。在Selenium2.0发布不久WebDriver就有过频繁的更新。请在这个连接 Maven Download Page确认当前的版本,相应地修改你工程中的pon.xml。
如今,你能够经过dos界面使用CD命令进入工程所在文件夹,经过如下命令运行Maven。编程
mvn clean install
运行以后会自动下载Selenium及相关套件,并加载到你的工程中去。c#
最后,将你的工程导入到你偏好的IDE中。若是你对导入的过程不是很清楚,咱们已经准备了操做指南。
Importing a maven project into IntelliJ IDEA.Importing a maven project into Eclipse
已经在Selenium1.0上构建测试工程的用户,咱们为您提供了一份指导如何将已有的代码迁移到Selenium2.0。Selenium2.0的首席开发工程师Simon Stewart为此撰写了一片文章:Magrating From Selenium RC to Selenium WebDriver。
如今你确定跃跃欲试要写一些代码了。咱们以一个简单的例子来开始第一段旅程:在Google上搜索“Cheese”,并打印出搜索结果网页的标题。
package org.openqa.selenium.example; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.WebDriverWait; public class Selenium2Example { public static void main(String[] args) { // 建立一个FirefoxDriver实例 // 这个类依赖于接口而不是接口的实现 WebDriver driver = new FirefoxDriver(); // 使用get方法访问Google driver.get("http://www.google.com"); // 使用下面这个方法也可以达到访问Google的目的 // driver.navigate().to("http://www.google.com"); // 找到html输入框的name WebElement element = driver.findElement(By.name("q")); // 输入要查找的内容 element.sendKeys("Cheese!"); // 提交表单,WebDriver会自动找到咱们须要提交的元素所在的表单 element.submit(); // 打印网页的标题 System.out.println("Page title is: " + driver.getTitle()); // Google的搜索网页会经过JS动态渲染 // 等待页面加载完毕,超时时间为10秒 (new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return d.getTitle().toLowerCase().startsWith("cheese!"); } }); // 控制台上将打印以下信息: "cheese! - Google Search" System.out.println("Page title is: " + driver.getTitle()); // 关闭浏览器 driver.quit(); } }
在本章节的接下来篇幅,咱们将学习如何使用WebDriver操做你的浏览器,如何使用框架和窗口来测试Web网站。固然,咱们将提供更加翔实的论述和举例。
driver.get("http://www.google.com");在某些状况下,好比操做系统和浏览器的穿插组合,WebDriver有可能不会等待Web页面加载完成,这种状况下WebDriver会返回错误或者直接运行下一步操做。为了保证程序的健壮性,你须要等待页面中某个元素加载完成后再进行下一步操做,请参考 Explicit and Implicit Waits。
<div id="coolestWidgetEvah">...</div> WebElement element = driver.findElement(By.id("coolestWidgetEvah"));
By Class Name
在这种场景下,咱们引用DOM元素的属性。实际状况是不少元素都有同样的Class Name,所以找到多个有相同Class Name的元素,比找到第一个拥有这个Class Name的元素来的更重要。
示例:如何使用该方法定位元素
<div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div> List<WebElement> cheeses = driver.findElements(By.className("cheese"));
DOM元素Tag的名称。
示例:如何使用该方法定位元素
<iframe src="..."></iframe> WebElement frame = driver.findElement(By.tagName("iframe"));
找到与Name属性相同的Input元素。
示例:如何使用该方法定位元素
<input name="cheese" type="text"/> WebElement cheese = driver.findElement(By.name("cheese"));
找到与Text属性精确匹配的超连接。
示例:如何使用该方法定位元素
<a href="http://www.google.com/search?q=cheese">cheese</a> WebElement cheese = driver.findElement(By.linkText("cheese"));
找到与Text属性模糊匹配的超连接。
示例:如何使用该方法定位元素<a href="http://www.google.com/search?q=cheese">search for cheese</a> WebElement cheese = driver.findElement(By.partialLinkText("cheese"));
示例:如何使用该方法定位元素
<div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div> WebElement cheese = driver.findElement(By.cssSelector("#food span.dairy.aged"));
By XPath
当有须要时,WebDriver还可使用浏览器自带的XPATH。对于那些不支持XPATH的浏览器,咱们提供了WebDriver特有的实现方式。请确保熟悉XPATH在不一样的引擎中的区别,不然会致使一些不可预料的问题。
Driver | 大小写敏感 | 属性值是否可见 | 是否支持XAPTH |
HtmlUnit Driver | 仅识别小写 | 可见 | 是 |
IE Driver | 仅识别小写 | 可见 | 否 |
FireFox Diver | 大小写不敏感 | 可见 | 是 |
上面的表格有一些抽象,让咱们来看个例子
<input type="text" name="example" /> <INPUT type="text" name="other" /> List<WebElement> inputs = driver.findElements(By.xpath("//input"));
匹配结果以下
XPATH表达式 | HtmlUnit Driver | FireFox Driver | IE Driver |
//input | 1 | 2 | 2 |
//INPUT | 0 | 2 | 0 |
有些标签的属性有默认值,这种状况下不指定属性值则匹配默认值。好比,"input"标签"type"属性默认为"text"。使用XPATH的首要原则就是不要忽略这些隐藏的实现。
使用JavaScript
只要返回的是一个Web Element,你还可使用任意的JS代码查找Web元素,根据查询结果会自动修改成一个WebElement对象。
一个简单的使用jQuery的例子:
WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]");
查找页面中每一个label的全部Input元素:
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);
WebElement select = driver.findElement(By.tagName("select")); List<WebElement> allOptions = select.findElements(By.tagName("option")); for (WebElement option : allOptions) { System.out.println(String.format("Value is: %s", option.getAttribute("value"))); option.click(); }
Select select = new Select(driver.findElement(By.tagName("select"))); select.deselectAll(); select.selectByVisibleText("Edam");
driver.findElement(By.id("submit")).click();
element.submit();
driver.switchTo().window("windowName");
<a href="somewhere.html" target="windowName">Click here to open a new window</a>
for (String handle : driver.getWindowHandles()) { driver.switchTo().window(handle); }
driver.switchTo().frame("frameName");
driver.switchTo().frame("frameName.0.child");以上方法将切换到名称为“frameName”的Frame的第一个子Frame,全部Frame都是Web页面的最顶端开始计数。
Alert alert = driver.switchTo().alert();
前文中,咱们使用get方法来获取网页(driver.get("http://www.example.com"))。正如你看到的,WebDriver有很多轻量级的功能聚焦的接口,Navigation就是这样一个。正由于加载网页是一个再普通不过的需求,这个方法存在于Driver类下面,可是用法很简单:
driver.navigate().to("http://www.example.com");
重申一下,"navigate().to()"和"get()"作的是一样的事情,只不过其中一个更适合打印。
Navigate接口还提供方法能够在浏览器历史记录中先后翻页。
driver.navigate().forward(); driver.navigate().back();
请注意,以上功能彻底取决于底层的浏览器。若是你习惯跨浏览器操做,当你使用这些接口时可能会出现意想不到的的异常。
// 打开Cookie做用的网站 driver.get("http://www.example.com"); // 设置全局Cookie Cookie cookie = new Cookie("key", "value"); driver.manage().addCookie(cookie); // 输出当前网页全部可用的Cookie Set<Cookie> allCookies = driver.manage().getCookies(); for (Cookie loadedCookie : allCookies) { System.out.println(String.format("%s -> %s", loadedCookie.getName(), loadedCookie.getValue())); } // 你又三种方法删除Cookie // By name driver.manage().deleteCookieNamed("CookieName"); // By Cookie driver.manage().deleteCookie(loadedCookie); // Or all of them driver.manage().deleteAllCookies();
FirefoxProfile profile = new FirefoxProfile(); profile.addAdditionalPreference("general.useragent.override", "some UA string"); WebDriver driver = new FirefoxDriver(profile);
下面是一个拖拽Web页面元素的例子,前提是本地事件必须可用。
WebElement element = driver.findElement(By.name("source")); WebElement target = driver.findElement(By.name("target")); (new Actions(driver)).dragAndDrop(element, target).perform();
译者注:
一、原文连接:http://www.seleniumhq.org/docs/03_webdriver.jsp。
二、文中只包含了java相关的操做,WebDriver还支持c#/Python/Ruby/Perl/PHP/Perl,若有须要,请阅读原文。
三、language binding,又叫glue code,意思是胶水代码,好比有个C++的lib库,java调用这个库的api就叫java binding。参考:http://en.wikipedia.org/wiki/Language_binding。
四、措辞拙劣,有些单词句子没有深究就直译了,深感从阅读到翻译差的不只仅是一本字典,还有文化的差别。笔者强烈推荐直接阅读官网上的原文,若是个人译文给你形成误解,深感不安。这也是最后三章不敢继续班门弄斧的缘由,等我对Selenium熟悉了以后再回来补全。