请确认你使用的WebDriver是最新的当前版本。在这篇文档撰写时,上述示例给出的是最新的版本。在Selenium2.0发布不久WebDriver就有过频繁的更新。请在这个链接MavenDownloadPage确认当前的版本,相应地修改你工程中的pon.xml。
已经在Selenium1.0上构建测试工程的用户,我们为您提供了一份指导如何将已有的代码迁移到Selenium2.0。Selenium2.0的首席开发工程师SimonStewart为此撰写了一片文章:MagratingFromSeleniumRCtoSeleniumWebDriver。
WebDriver可以用来实现Web应用程序的自动化测试,特别适合于验证实际结果是否符合预期结果的场景。WebDriver旨在提供比Selenium1.0更加易用、友好的API,便于用户的探索和理解,从而使测试用例变得容易阅读和维护。WebDriver没有使用任何第三方测试框架,所以它可以很好与单元测试工具或者最古老的main函数结合使用。本章节将介绍如何使用WebDriver的API,帮助你慢慢开始了解WebDriver。如果你还没有新建一个Selenium工程,请先完成这个操作,在这个章节的上面有详细的描述。
当你创建完Selenium工程后,你会发现WebDriver和普通的第三方库一样是完全独立的,在你使用之前不需要启动任何额外的进程或者安装程序,相反如果你使用Selenium-RC需要先启动代理服务器。
注意:当你使用如下WebDriver时需要额外的步骤:ChromeDriver,OperaDriver,AndroidDriver,IPhoneDriver。
在某些情况下,比如操作系统和浏览器的穿插组合,WebDriver有可能不会等待Web页面加载完成,这种情况下WebDriver会返回错误或者直接运行下一步操作。为了保证程序的健壮性,你需要等待页面中某个元素加载完成后再进行下一步操作,请参考ExplicitandImplicitWaits。
我们可以通过WebDriver实例或者WebElement类来定位UI元素。我们为每种编程语言都提供了两种方法:“FindElement”和“FindElements”。第一种方法返回的一个WebElement,找不到则抛出异常。第二个方法返回一个WebElement链表(List),在找不到任何DOM元素的情况下会返回空的链表。
当我们定位一个UI元素,这个是最有效也是最好的方法。不过这个方法不是万能的,有的前端开发在设计UI元素时会遗漏ID或者使用动态ID,这两种情况下都要避免使用这个方法。这时候使用获取class名称方法比ByID更合适。
WebElementelement=driver.findElement(By.id("coolestWidgetEvah"));
ByClassName
在这种场景下,我们引用DOM元素的属性。实际情况是很多元素都有一样的ClassName,因此找到多个有相同ClassName的元素,比找到第一个拥有这个ClassName的元素来的更重要。
示例:如何使用该方法定位元素
<divclass="cheese"><span>Cheddar</span></div><divclass="cheese"><span>Gouda</span></div>
List<WebElement>cheeses=driver.findElements(By.className("cheese"));
ByTagName
DOM元素Tag的名称。
示例:如何使用该方法定位元素
<iframesrc="..."></iframe>
WebElementframe=driver.findElement(By.tagName("iframe"));
ByName
找到与Name属性相同的Input元素。
示例:如何使用该方法定位元素
<inputname="cheese"type="text"/>
WebElementcheese=driver.findElement(By.name("cheese"));
ByLinkText
找到与Text属性精确匹配的超链接。
示例:如何使用该方法定位元素
<ahref="http://www.google.com/search?q=cheese">cheese</a>
WebElementcheese=driver.findElement(By.linkText("cheese"));
ByPartialLinkText
找到与Text属性模糊匹配的超链接。
示例:如何使用该方法定位元素
<ahref="http://www.google.com/search?q=cheese">searchforcheese</a>
WebElementcheese=driver.findElement(By.partialLinkText("cheese"));
ByCSS
这个方法名称意味着它是一个CSS探测器。前提是浏览器默认支持这种方法,建议根据W3C的标准文档构建CSS选择器。如果浏览器不支持CSS选择器,可以使用Sizzle。IE6,7和FireFox3.0就是使用Sizzle作为CSS查询引擎。
注意不是所有浏览器都使用同样的CSS选择器表达式,有些CSS可能只在某一个版本中生效。
示例:如何使用该方法定位元素
<divid="food"><spanclass="dairy">milk</span><spanclass="dairyaged">cheese</span></div>
WebElementcheese=driver.findElement(By.cssSelector("#foodspan.dairy.aged"));
ByXPath
当有需要时,WebDriver还可以使用浏览器自带的XPATH。对于那些不支持XPATH的浏览器,我们提供了WebDriver特有的实现方式。请确保熟悉XPATH在不同的引擎中的区别,否则会导致一些不可预料的问题。
Driver大小写敏感属性值是否可见是否支持XAPTH
HtmlUnitDriver仅识别小写可见是
IEDriver仅识别小写可见否
FireFoxDiver大小写不敏感可见是上面的表格有一些抽象,让我们来看个例子
<inputtype="text"name="example"/>
<INPUTtype="text"name="other"/>
List<WebElement>inputs=driver.findElements(By.xpath("//input"));
匹配结果如下
XPATH表达式HtmlUnitDriverFireFoxDriverIEDriver
//input122
//INPUT020有些标签的属性有默认值,这种情况下不指定属性值则匹配默认值。比如,"input"标签"type"属性默认为"text"。使用XPATH的首要原则就是不要忽略这些隐藏的实现。
使用JavaScript
只要返回的是一个WebElement,你还可以使用任意的JS代码查找Web元素,根据查询结果会自动修改为一个WebElement对象。
一个简单的使用jQuery的例子:
WebElementelement=(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( "varlabels=arguments[0],inputs=[];for(vari=0;i<labels.length;i++){"+ "inputs.push(document.getElementById(labels[i].getAttribute('for')));}returninputs;",labels); |
7.3模拟用户输入行为
我们已经演示了在文本框输入文本内容,其他Web元素应该如何操作呢?你可以触发CheckBox的某个选项,也可以选择Select的某个选项。WebDriver处理Select元素也很简单。
WebElementselect=driver.findElement(By.tagName("select")); List<WebElement>allOptions=select.findElements(By.tagName("option")); for(WebElementoption:allOptions){ System.out.println(String.format("Valueis:%s",option.getAttribute("value"))); option.click(); } |
上面的例子,将选择Web页面中的第一个Select元素,并将循环打印出选项的取值并单击选项。或许你已经注意到,使用这个方法并不是最有效的。WebDriver提供一个“Select”类,这个类的方法更适合于处理上述这种场景。
Selectselect=newSelect(driver.findElement(By.tagName("select"))); select.deselectAll(); select.selectByVisibleText("Edam"); |
上面的例子,首先去除选定第一个选项的焦点,然后选中取值为"Edam"的选项。
一旦你完成了所有表单字段的输入,下一步就是提交表单。一种方法就是找到Web页面中的Submit按钮并单击:
driver.findElement(By.id("submit")).click();
作为另一种选择,WebDriver的Element类有一个更加便利的方法"sublmit"。如果你对表单中的某个Element使用该方法,WebDriver将会走读其所在的DOM对象,直到找到其所属的表单,并提交。如果该Element并不在某个表单中,将会抛出异常NoSuchElementException。
element.submit();
7.4在windows和frames间切换
有些Web程序包含许多Frame和窗口,WebDriver提供"switchto"方法在这之间进行切换:
driver.switchTo().window("windowName");
所有传输给WebDriver的指定将被传输给切换后的窗口。如何直到窗口的名称呢?查看JS并打开该窗口就可以了:
<ahref="somewhere.html"target="windowName">Clickheretoopenanewwindow</a>
作为另一种选择,你可以使用一个“窗口句柄”传递给"switchTo().window()"方法。根据此方法,将会使用迭代器遍历所有打开的窗口:
for(Stringhandle:driver.getWindowHandles()){
driver.switchTo().window(handle);
}
你也可以在Frame之间切换(或者进入Frame):
driver.switchTo().frame("frameName");
你还可以根据路径使用Frame的子Frame,而且可以通过索引定位Frame。
driver.switchTo().frame("frameName.0.child");
以上方法将切换到名称为“frameName”的Frame的第一个子Frame,所有Frame都是Web页面的最顶端开始计数。
7.5弹出框
Selenium2.0beta1版本,我们提供方法获取弹出框。在你触发弹出框的操作后,你可以用一下方法进入弹出框:
Alertalert=driver.switchTo().alert();
以上方法将会返回当前当前打开的alert对象,你可以对这个对象进行任何可操作:点击取消,点击确定,关闭窗口,获取alert的文本内容等。这个接口在alerts、confirms、prompts对象上都有很好的应用,具体请参见API文档。
7.6Navigation:浏览器本地历史记录
前文中,我们使用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();
请注意,以上功能完全取决于底层的浏览器。如果你习惯跨浏览器操作,当你使用这些接口时可能会出现意想不到的的异常。
7.7Cookies
在我们开始下一步的讲解之前,你可能对WebDriver如何操作本地Cookies很感兴趣。首先,你必须处于当前Cookie的作用域。如果你在打开一个网页之前尝试预置Cookie,而且你的主页大到需要很长一段时间来加载,这时候你需要找一个小点的网页来替代,比如HTTP404网页(http://example.com/some404page)。
//打开Cookie作用的网站 driver.get("http://www.example.com"); //设置全局Cookie Cookiecookie=newCookie("key","value"); driver.manage().addCookie(cookie); //输出当前网页所有可用的Cookie Set<Cookie>allCookies=driver.manage().getCookies(); for(CookieloadedCookie:allCookies){ System.out.println(String.format("%s->%s",loadedCookie.getName(),loadedCookie.getValue())); } //你又三种方法删除Cookie //Byname driver.manage().deleteCookieNamed("CookieName"); //ByCookie driver.manage().deleteCookie(loadedCookie); //Orallofthem driver.manage().deleteAllCookies(); |
7.8修改用户代理服务器
对于FireFox来说很简单:
FirefoxProfileprofile=newFirefoxProfile(); profile.addAdditionalPreference("general.useragent.override","someUAstring"); WebDriverdriver=newFirefoxDriver(profile); |
7.9拖拽Web元素
下面是一个拖拽Web页面元素的例子,前提是本地事件必须可用。
WebElementelement=driver.findElement(By.name("source"));
WebElementtarget=driver.findElement(By.name("target"));
(newActions(driver)).dragAndDrop(element,target).perform();
8各种Driver的特性以及如何选择合适Driver
翻译中
9向前兼容:融合WebDriver和Selenium-RC
翻译中
10为远程WebDriver单独启动SeleniumServer
翻译中
译者注:
1、原文链接:http://www.seleniumhq.org/docs/03_webdriver.jsp。
2、文中只包含了java相关的操作,WebDriver还支持c#/Python/Ruby/Perl/PHP/Perl,如有需要,请阅读原文。
3、languagebinding,又叫gluecode,意思是胶水代码,比如有个C++的lib库,java调用这个库的api就叫javabinding。参考:http://en.wikipedia.org/wiki/Language_binding。
4、措辞拙劣,有些单词句子没有深究就直译了,深感从阅读到翻译差的不仅仅是一本字典,还有文化的差异。笔者强烈推荐直接阅读官网上的原文,如果我的译文给你造成误解,深感不安。这也是最后三章不敢继续班门弄斧的原因,等我对Selenium熟悉了之后再回来补全。