被selenium webdriver中的定位虐过,决定过一遍这方面的知识点,记录下踩过的坑。
好,来认识下selenium webdriver及其使用。
几个概念
Selenium
Selenium is a set of different software tools each with a different approach to supporting test automation.
一套用于进行浏览器自动化测试的开源工具集。selenium的一个重要特性是支持所有主流浏览器(chrome,Firefox,IE,Safari)。
selenium产生于2004年,由Jason Huggins开发,起因是他为了解决每次更新应用时,需要手动测试带来的低效,他通过开发一个JavaScript的library,实现与页面进行交互,从而可以在多个浏览器之间实现测试自动化。而这个library最终成为了后来selenium的内核(Selenium Core)。
selenium test支持的语言: Java, C#, Javascript,python,ruby
Webdriver
06年,Google的一位工程师Simon Stewart开始着手一个项目,由于Selenium的起源是一个 JavaScript的library,Simon希望开发出一个可以直接与浏览器进行交互的测试工具,通过使用浏览器和操作系统的原生methods,以避免来自JavaScript环境的限制, 这个项目就是WebDriver,这也是webdriver的由来。
你可以理解成它是一个开源项目,可以让用户编写各种操作代码,这些代码可以在主流浏览器上运行,与页面进行交互。
Selenium Webdriver
08年,Selenium 与 Webdriver联姻,二者merge了。merge的原因?Simon Stewart的原话:
‘’Why are the projects merging? Partly because WebDriver addresses some shortcomings in selenium (by being able to bypass the JS sandbox, for example. And we’ve got a gorgeous API), partly because selenium addresses some shortcomings in WebDriver (such as supporting a broader range of browsers) and partly because the main selenium contributors and I felt that it was the best way to offer users the best possible framework’‘
我简单地理解成各有千秋,互补增强。
使用
基本用法其实就是定位到页面指定的元素,然后对元素进行操作,比如单击、滚动、输入等等。
看一段简单的ruby代码:
# require selenium-webdriver module
require "selenium-webdriver"
# 打开一个Firefox的浏览器,也可以打开chrome,IE,将:firefox换成:chrome, :ie
driver = Selenium::WebDriver.for :firefox
# 打开网页
driver.navigate.to "http://www.google.com"
# 定位元素
element = driver.find_element(:name, 'q')
# 对元素进行操作
element.send_keys "Hello Selenium WebDriver!"
element.submit
定位及操作
find_element: 查找匹配到的第一个元素
find_elements: 查找匹配到的所有元素
在Selenium webdriver中,主要有以下几类:
ID
通过ID来定位元素,ID是唯一的,通常较少变动,所以可以很准确地定位到指定元素。
比如:
element = driver.find_element(:id, "username") element.send_keys("admin") driver.find_element(:id, "submit").click
Name
Name也是比较常用的定位方式
element = driver.find_element(:name, "username") driver.find_element(:name, "comment").send_keys("my comments")
Link Text
只用于超链接元素的定位
driver.find_element(:link_text, "Cancel").click driver.find_element(:link, "Login")
Partial Link Text
selenium 允许通过一部分的超链接文本来定位某个超链接,比如:
# 点击到“cancel” 或者“Cancel”链接 driver.find_element(:partial_link_text, "ancel").click
XPath
Xpath 几乎可以定位到页面上的任何一个元素。XPath是XML path的简称,它有两种用法:
- 绝对路径, 用”/“, 例如:
/html/body/table[1]
- 相对路径,用”//“
例如:
driver.find_element(:xpath, "//*[@id='div2']/input[@type='checkbox']").click driver.find_element(:xpath,"//input[@value='Sign in']") driver.find_element(:xpath, "//a[@href='/logout']").click
一般不推荐用绝对路径,因为一旦页面结构发生变化,该路径随之失效。
- 绝对路径, 用”/“, 例如:
Tag Name
通过元素的标签名称来查找元素,不过这种方法找到的元素通常不止一个。
driver.find_element(:tag_name, "body") driver.find_element(:tag_name, "body").text # 查看button的个数 button_elems = driver.find_elements(:tag_name, "button") button_elems.count
Class Name
这是利用元素的css样式表所引用的类名称来进行查找,不过当某个元素含有多个类时,不可以使用多个类来查找。
例如如下的HTML:
<a href="back.html" class="btn btn-default">Cancel</a> <input type="submit" class="btn btn-deault btn-primary">Submit</input>
对应的元素定位:
driver.find_element(:class, "btn-primary").click # Submit button driver.find_element(:class, "btn").click # Cancel link
这里Cancel和Submit都有”btn”这个class,find_element会返回匹配到的第一个元素,所以
driver.find_element(:class, "btn").click
点击的是cancel这个button。但是不允许指定多个class,下面这样的用法是错误的:
driver.find_element(:class, "btn btn-deault btn-primary").click
如果想要定位带有多个class的元素,怎么办?可以使用CSS Selector。
CSS Selector
定位ID为login的元素下面的text,可以这么写:
driver.find_element(:css, "#login > input[type='text']").click
当需要指定多个属性值时,可以逐一加在后面,比如:
driver.find_element(:css, "#login > input[type='text'][name = 'username']")
而上面多个class的情况,可以这么写:
driver.find_element(:css, "input.btn.btn-deault.btn-primary").click
小结:
看过一些前辈写的相关文章,里面提到定位的一些原则,比如:Xpath很强大,但是非常费时,需要扫描整个网页来定位,尽量少用。Css selector与xpath比较类似,但是执行速度要更快,有ID的尽量用ID,别浪费。
参考
另,推荐一个小册子:Selenium WebDriver Recipes in Ruby