注意:我们正致力于完善帮助指南的每一个章节,虽然这个章节仍然存在需要完善的地方,不过我们坚信当前你看到的帮助信息是精确无误的,后续我们会提供更多的指导信息来完善帮助文档。
1.WebDriver介绍
Selenium2.0最主要的新特性就是集成了WebDriverAPI。我们设计WebDriver的初衷是提供更加简单明了的接口来弥补Selenium-RCAPI的不足。在动态网页中,通常只会更新局部的html元素,WebDriver会很好的帮助用户快速定位这些元素。我们最终的目的是通过提供精心设计的面向对象API来解决现代高级网页中的测试难题。
2.WebDriver如何驱动浏览器?与Selenium-RC有什么区别?
不同类型的浏览器都会有原生的接口支持自动化操作,Selenium通过这些接口直接向浏览器发送指令。如何发送这些指令取决于你当前使用的浏览器类型,我们将在这一章节后面来详细介绍。
看上去WebDriver与之前Selenium-RC的实现方式类似,实际上两者之间存在着本质的区别。对于所有类型的浏览器Selenium-RC都是使用的同一种方法:当浏览器启动时,向其中注入javascript,从而使用这些js来驱动浏览器中的AUT(ApplicationUnderTest)。WebDriver并没有使用这种技术,它是通过调用浏览器原生的自动化API直接驱动浏览器。
3.WebDriver与SeleniumServer
是否需要是用SeleniumServer取决于你使用WebDriver的方式。以下两种情况不需要使用SeleniumServer,WebDriver直接运行浏览器即可:1、testcases仅仅使用了Webdriver的API;2、浏览器和testcase在同一台PC上,而且testcases仅仅使用了Webdriver的API。
以下三种情况你需要结合SeleniumServer来使用WebDriver:
1)使用Selenium-Grid管理集群环境(或者虚拟机)上的testcase;
2)需要调用非本机上的不同版本的浏览器;
3)未使用任何languagebinding(java/c#/python/ruby),且有意向使用HtmlUnitDriver。
4.配置Selenium-WebDriver工程
安装Selenium是指在开发环境上配置一个工程,然后可以在这个工程中用Selenium编写程序。如何配置取决于你使用的开发语言和编程环境。
Java
使用Maven是配置一个Selenium2.0java工程最简单的方式。Maven会下载所有javabingdings以及所有相关的库(theSelenium2.0javaclientlibrary)。通过使用pom.xml(maven配置文件)来新建工程,你可以根据自己的喜好将Maven工程导入IntelliJIDEA或者Eclipse。
首先,创建一个文件夹存放Maven工程文件。然后,创建pom.xml,你可以使用texteditor来编辑。鉴于已经有很多关于“如何在Maven工程中使用pom.xml”优秀的参考文献,这里将不再过多的讨论相关细节。下面给出一个示例,为你的工程也创建一个类似的文件。
请确认你使用的WebDriver是最新的当前版本。在这篇文档撰写时,上述示例给出的是最新的版本。在Selenium2.0发布不久WebDriver就有过频繁的更新。请在这个链接MavenDownloadPage确认当前的版本,相应地修改你工程中的pon.xml。
现在,你可以通过dos界面使用CD命令进入工程所在文件夹,通过以下命令运行Maven。
mvncleaninstall
运行之后会自动下载Selenium及相关套件,并加载到你的工程中去。
最后,将你的工程导入到你偏好的IDE中。如果你对导入的过程不是很清楚,我们已经准备了操作指南。
ImportingamavenprojectintoIntelliJIDEA. ImportingamavenprojectintoEclipse
C#
对于Selenium2.2.0,C# bingdings以一组有签名的dll文件和一些被依赖的dll文件发布,Selenium2.2.0之前,Selenium所有的dll文件都没有签名。通过从https://code.google.com/p/selenium/downloads/list.下载最新的Selenium-dotnetzip文件,就可以在你的工程中添加Selenium。如果你的操作系统为Windows Vista及以上,在解压zip文件之前,要先解锁压缩文件—通过右键—》属性—Unlock,然后确定。
解压完成后,将每个解压出的dll文件添加一个引用到你在visualstudio中的工程中(或根据你选择的IDE)
NuGetPackages: RC WebDriver WebDriverBackedSelenium Support
Python
如果你比较熟悉python,你可以使用python进行自动化测试,运行下面的命令就可以将selenium添加到你的python开发环境中:
pip install selenium
Pip requires pip to beinstalled, pip also has a dependency on setuptools. Python编程超出了本章的范围,但是你身边有许多资源供你快速学习。
Ruby
如果你比较熟悉ruby,你可以使用ruby进行自动化测试,运行下面的命令就可以将selenium添加到你的ruby开发环境中:
gem install selenium-webdriver
Pip requires pip to beinstalled, pip also has a dependency on setuptools. Python编程超出了本章的范围,但是你身边有许多资源供你快速学习。
Perl
Perl binding是由第三方提供,请参考任何他们的关于如何安装/上手的文件。有一个有名的文章介绍Perlbinding。
PHP
PHP binding是由第三方提供,请参考任何他们的关于如何安装/上手的文件。有三篇有名的文章ByChibimagic ByLukasz Kolczynski and Bythe Facebook
5.如何将自动化工程从Selenium1.0迁移到Selenium2.0
已经在Selenium1.0上构建测试工程的用户,我们为您提供了一份指导如何将已有的代码迁移到Selenium2.0。Selenium2.0的首席开发工程师SimonStewart为此撰写了一片文章:
Migrating FromSelenium RC to Selenium WebDriver
6.Selenium-WebDriverAPI简介
WebDriver可以用来实现Web应用程序的自动化测试,特别适合于验证实际结果是否符合预期结果的场景。WebDriver旨在提供比Selenium1.0更加易用、友好的API,便于用户的探索和理解,从而使测试用例变得容易阅读和维护。WebDriver没有使用任何第三方测试框架,所以它可以很好与单元测试工具或者最古老的main函数结合使用。本章节将介绍如何使用WebDriver的API,帮助你慢慢开始了解WebDriver。如果你还没有新建一个Selenium工程,请先完成这个操作,在这个章节的上面有详细的描述。
当你创建完Selenium工程后,你会发现WebDriver和普通的第三方库一样是完全独立的,在你使用之前不需要启动任何额外的进程或者安装程序,相反如果你使用Selenium-RC需要先启动代理服务器。
注意:当你使用如下WebDriver时需要额外的步骤: ChromeDriver, OperaDriver, AndroidDriver and iOS Driver
现在你肯定跃跃欲试要写一些代码了。我们以一个简单的例子来开始第一段旅程:在Google上搜索“Cheese”,并打印出搜索结果网页的标题。其他语言见原文
在本章节的接下来篇幅,我们将学习如何使用WebDriver操作你的浏览器,如何使用框架和窗口来测试Web网站。当然,我们将提供更加翔实的论述和举例。
7.Selenium-WebDriverAPI详解
7.1获取Web页面
我们第一件要做的事是通过WebDriver取得Web页面的控制权,一般情况下使用get方法
driver.get("http://www.google.com");
在某些情况下,比如操作系统和浏览器的穿插组合,WebDriver有可能不会等待Web页面加载完成,这种情况下WebDriver会返回错误或者直接运行下一步操作。为了保证程序的健壮性,你需要等待页面中某个元素加载完成后再进行下一步操作,请参考Explicit andImplicit Waits.
7.2定位UI元素
我们可以通过WebDriver实例或者WebElement类来定位UI元素。我们为每种编程语言都提供了两种方法:“FindElement”和“FindElements”。第一种方法返回的一个WebElement,找不到则抛出异常。第二个方法返回一个WebElement链表(List),在找不到任何DOM元素的情况下会返回空的链表。
Find方法会使用类似探测器的类,类名叫做By。下面列举By的一些常用方法:
By ID
当我们定位一个UI元素,这个是最有效也是最好的方法。不过这个方法不是万能的,有的前端开发在设计UI元素时会遗漏ID或者使用动态ID,这两种情况下都要避免使用这个方法。这时候使用获取class名称方法比By ID更合适。
示例:如何使用该方法定位元素
<divid="coolestWidgetEvah">...</div>
WebElement element = driver.find_element_by_id("coolestWidgetEvah")
or
fromselenium.webdriver.common.byimport By
WebElement element = driver.find_element(by=By.ID, value="coolestWidgetEvah")
By ClassName
在这种场景下,我们引用DOM元素的属性。实际情况是很多元素都有一样的ClassName,因此找到多个有相同ClassName的元素,比找到第一个拥有这个ClassName的元素来的更重要。
示例:如何使用该方法定位元素
<divclass="cheese"><span>Cheddar</span></div><divclass="cheese"><span>Gouda</span></div>
List<WebElement> cheeses = driver.find_elements_by_class_name("cheese")
or
fromselenium.webdriver.common.byimport By
List<WebElement> cheeses = driver.find_elements(By.CLASS_NAME, "cheese")
ByTagName
DOM元素Tag的名称。
示例:如何使用该方法定位元素
<iframesrc="..."></iframe>
WebElement frame = driver.find_element_by_tag_name("iframe")
or
fromselenium.webdriver.common.byimport By
WebElement frame = driver.find_element(By.TAG_NAME, "iframe")
ByName
找到与Name属性相同的Input元素。
示例:如何使用该方法定位元素
<inputname="cheese"type="text"/>
WebElement cheese = driver.find_element_by_name("cheese")
or
fromselenium.webdriver.common.byimport By
WebElement cheese = driver.find_element(By.NAME, "cheese")
ByLinkText
找到与Text属性精确匹配的超链接。
示例:如何使用该方法定位元素
<ahref="http://www.google.com/search?q=cheese">cheese</a>>
cheese = driver.find_element_by_link_text("cheese")
or
fromselenium.webdriver.common.byimport By
cheese = driver.find_element(By.LINK_TEXT, "cheese")
找到与Text属性模糊匹配的超链接。
示例:如何使用该方法定位元素
<ahref="http://www.google.com/search?q=cheese">search for cheese</a>>
cheese = driver.find_element_by_partial_link_text("cheese")
or
fromselenium.webdriver.common.byimport By
cheese = driver.find_element(By.PARTIAL_LINK_TEXT, "cheese")
By CSS
这个方法名称意味着它是一个CSS探测器。前提是浏览器默认支持这种方法,建议根据W3C的标准文档构建CSS选择器。如果浏览器不支持CSS选择器,可以使用Sizzle。IE6,7和FireFox3.0就是使用Sizzle作为CSS查询引擎。
注意不是所有浏览器都使用同样的CSS选择器表达式,有些CSS可能只在某一个版本中生效。
示例:如何使用该方法定位元素
<divid="food"><spanclass="dairy">milk</span><spanclass="dairy aged">cheese</span></div>
cheese = driver.find_element_by_css_selector("#food span.dairy.aged")
or
fromselenium.webdriver.common.byimport By
cheese = driver.find_element(By.CSS_SELECTOR, "#food span.dairy.aged")
By XPath
当有需要时,WebDriver还可以使用浏览器自带的XPATH。对于那些不支持XPATH的浏览器,我们提供了WebDriver特有的实现方式。请确保熟悉XPATH在不同的引擎中的区别,否则会导致一些不可预料的问题。
Driver | 大小写敏感 | 属性值是否可见 | 是否支持XPath |
HtmlUnit Driver | 仅识别小写 | 可见 | 是 |
Internet Explorer Driver | 仅识别小写 | 可见 | 否 |
Firefox Driver | 大小写不敏感 | 可见 | 是 |
上面的表格有一些抽象,让我们来看个例子
<inputtype="text"name="example"/>
<INPUTtype="text"name="other"/>
---------------------------------------------------------------------
inputs = driver.find_elements_by_xpath("//input")
or
fromselenium.webdriver.common.byimport By
inputs = driver.find_elements(By.XPATH, "//input")
匹配结果如下
XPath expression | HtmlUnit Driver | Firefox Driver | Internet Explorer Driver |
//input | 1(“example”) | 2 | 2 |
//INPUT | 0 | 2 | 0 |
有些标签的属性有默认值,这种情况下不指定属性值则匹配默认值。比如,"input"标签"type"属性默认为"text"。使用XPATH的首要原则就是不要忽略这些隐藏的实现。在使用的webdriver时XPath的拇指法则是,你不应该期望能够匹配这些隐含的属性。
使用JavaScript
只要返回的是一个WebElement,你还可以使用任意的JS代码查找Web元素,根据查询结果会自动修改为一个WebElement对象。
一个简单的使用jQuery的例子:
element = driver.execute_script("return $('.cheese')[0]")
---------------------------------------------------------------------
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)
7.3模拟用户输入行为
我们已经演示了在文本框输入文本内容,其他Web元素应该如何操作呢?你可以触发CheckBox的某个选项,也可以选择Select的某个选项。WebDriver处理Select元素也很简单。
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()
上面的例子,将选择Web页面中的第一个Select元素,并将循环打印出选项的取值并单击选项。或许你已经注意到,使用这个方法并不是最有效的。WebDriver提供一个“Select”类,这个类的方法更适合于处理上述这种场景。
# available since 2.12
fromselenium.webdriver.support.uiimport Select
select = Select(driver.find_element_by_tag_name("select"))
select.deselect_all()
select.select_by_visible_text("Edam")
上面的例子,首先去除选定第一个选项的焦点,然后选中取值为"Edam"的选项。
一旦你完成了所有表单字段的输入,下一步就是提交表单。一种方法就是找到Web页面中的Submit按钮并单击:
driver.find_element_by_id("submit").click()
作为另一种选择,WebDriver的Element类有一个更加便利的方法"sublmit"。如果你对表单中的某个Element使用该方法,WebDriver将会走读其所在的DOM对象,直到找到其所属的表单,并提交。如果该Element并不在某个表单中,将会抛出异常NoSuchElementException。
element.submit()
7.4在windows和frames间切换
有些Web程序包含许多Frame和窗口,WebDriver提供"switchto"方法在这之间进行切换
driver.switch_to.window("windowName")
所有传输给WebDriver的指定将被传输给切换后的窗口。如何知道窗口的名称呢?查看JS并打开该窗口就可以了:
<ahref="somewhere.html"target="windowName">Click here to open a new window</a>
作为另一种选择,你可以使用一个“窗口句柄”传递给"switchTo().window()"方法。根据此方法,将会使用迭代器遍历所有打开的窗口:
for handle in driver.window_handles:
driver.switch_to.window(handle)
你也可以在Frame之间切换(或者进入Frame):
driver.switch_to.frame("frameName")
你还可以根据路径使用Frame的子Frame,而且可以通过索引定位Frame。
driver.switch_to.frame("frameName.0.child")
以上方法将切换到名称为“frameName”的Frame的第一个子Frame,所有Frame都是Web页面的最顶端开始计数。
7.5弹出框
Selenium2.0 beta 1版本,我们提供方法获取弹出框。在你触发弹出框的操作后,你可以用一下方法进入弹出框:
alert = driver.switch_to.alert
# usage: alert.dismiss(), etc.
以上方法将会返回当前当前打开的alert对象,你可以对这个对象进行任何可操作:点击取消,点击确定,关闭窗口,获取alert的文本内容等。这个接口在alerts、confirms、prompts对象上都有很好的应用,具体请参见API文档。
7.6Navigation:浏览器本地历史记录
前文中,我们使用get方法来获取网页(driver.get("http://www.example.com"))。正如你看到的,WebDriver有不少轻量级的功能聚焦的接口,Navigation就是这样一个。正因为加载网页是一个再普通不过的需求,这个方法存在于Driver类下面,但是用法很简单:
driver.get("http://www.example.com") # python doesn't have driver.navigate
重申一下,"navigate().to()"和"get()"做的是同样的事情,只不过其中一个更适合打印。
Navigate接口还提供方法可以在浏览器历史记录中前后翻页。
driver.forward()
driver.back()
请注意,以上功能完全取决于底层的浏览器。如果你习惯跨浏览器操作,当你使用这些接口时可能会出现意想不到的的异常。
7.7Cookies
在我们开始下一步的讲解之前,你可能对WebDriver如何操作本地Cookies很感兴趣。首先,你必须处于当前Cookie的作用域。如果你在打开一个网页之前尝试预置Cookie,而且你的主页大到需要很长一段时间来加载,这时候你需要找一个小点的网页来替代,比如HTTP404网页
# 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()
7.8修改用户代理服务器
对于FireFox来说很简单:
FirefoxProfile profile = webdriver.FirefoxProfile()
profile.set_preference("general.useragent.override", "some UA string")
WebDriver driver = webdriver.Firefox(profile)
7.9拖拽Web元素
下面是一个拖拽Web页面元素的例子,前提是本地事件必须可用。
fromselenium.webdriver.common.action_chainsimport ActionChains
WebElement element = driver.find_element_by_name("source")
WebElement target = driver.find_element_by_name("target")
ActionChains(driver).drag_and_drop(element, target).perform()
8、各种Driver的特性以及如何选择合适Driver
WebDriver isthe name of the key interface against which tests should be written,有几个实现,包括:
HtmlUnit Driver
这是目前WebDriver最快和最轻量级的实现,从它的名字可以看出,它基于HtmlUnit,HtmlUnit是无GUI的WebBrowser的java实现,对于任何language binding(除了java),在使用这个HtmlUnit Driver时,都需要Selenium Server。
使用如下:
driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNIT.copy())
JavaScript inthe HtmlUnit Driver
有名的浏览器中没有一个在使用HtmlUnit的javascript 引擎(Rhino)。如果你使用Htmlunit测试javascript,结果会和这些浏览器差别很大。
当我提到javascript时,我实际上指的是“javascriptand dom”,虽然W3C定义了DOM,但是各个浏览器在DOM和javascript如何与DOM通信的实现差别很大,HtmlUnit has an impressively complete implementation of the DOM andhas good support for using JavaScript, but it is no different from any other browser:it has its own quirks and differences from both the W3C standard and the DOMimplementations of the major browsers, despite its ability to mimic otherbrowsers.
With WebDriver,we had to make a choice; do we enable HtmlUnit’s JavaScript capabilities andrun the risk of teams running into problems that only manifest themselvesthere, or do we leave JavaScript disabled, knowing that there are more and moresites that rely on JavaScript? We took the conservative approach, and bydefault have disabled support when we use HtmlUnit. With each release of bothWebDriver and HtmlUnit, we reassess this decision: we hope to enable JavaScriptby default on the HtmlUnit at some point.
FireFox Driver
使用Firefox插件控制Firefox浏览器。被使用的FirefoxProfile是从安装在机器上的Profile剥离出来的,只包含Selenium WebDriver.xpi(插件)
InternetExplorer Driver
通过一个dll文件控制,因此只能应用在windows平台。
ChromeDriver
Chrome Driver由chromium项目本身维护和支持。WebDriver通过chromedrivebinary文件与Chrome工作(可以在chromium下载页面找到)。使用时必须同时安装了chromedriver和某个版本chrome浏览器。Chromedriver需要被放在一处能被WebDriver自动找到的地方(通过设置环境变量path),
各种driver优缺点如下表:
| Pros | Cons |
HtmlUnit Driver | 1. Fastest implementation of WebDriver 2.A pure Java solution and so it is platform independent. 3. Supports JavaScript | 1.Emulates other browsers’ JavaScript behaviour (see below) |
Firefox Driver | 1.Runs in a real browser and supports JavaScript 2.Faster than the Internet Explorer Driver | Slower than the HtmlUnit Driver |
Internet Explorer driver | Runs in a real browser and supports JavaScript with all the quirks your end users see. | 1.Obviously the Internet Explorer Driver will only work on Windows! 2.Comparatively slow (though still pretty snappy :) 3.XPath is not natively supported in most versions. Sizzle is injected automatically which is significantly slower than other browsers and slower when comparing to CSS selectors in the same browser. 4.CSS is not natively supported in versions 6 and 7. Sizzle is injected instead. 5.CSS selectors in IE 8 and 9 are native, but those browsers don’t fully support CSS3 |
Chrome Driver | 1.Runs in a real browser and supports JavaScript 2.Because Chrome is a Webkit-based browser, the Chrome Driver may allow you to verify that your site works in Safari. Note that since Chrome uses its own V8 JavaScript engine rather than Safari’s Nitro engine, JavaScript execution may differ. | Slower than the HtmlUnit Driver |
译者注:
1、原文链接:http://docs.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、原译文连接:http://www.spasvo.com/ceshi/open/kygncsgj/Selenium/2014214135011.html