主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582http://blog.csdn.net/ant_ren/article/details/7970793

selenium与webdriver整合后,形成的新的测试工具叫做selenium2.x。在selenium1时间,selenium使用javascript来达到测试自动化的目标。

1. selenium RC

早期的Selenium使用的是Javascript注入技术与浏览器打交道, 需要Selenium RC启动一个Server,将操作Web元素的API调用转化为一段段Javascript,在Selenium内核启动浏览器之后注入这段 Javascript。开发过Web应用的人都知道,Javascript可以获取并调用页面的任何元素,自如的进行操作。由此才实现了Selenium 的目的:自动化Web操作。这种Javascript注入技术的缺点是速度不理想,而且稳定性大大依赖于Selenium内核对API翻译成的 Javascript质量高低。

启动Selenium Server以及RC至今为止还保留着,应该是考虑到向前兼容吧,命令如下:

  1. java -jar selenium-server-standalone-2.14.0.jar -role hub
  2. java -jar selenium-server-standalone-2.14.0.jar -role node  -hub http://localhost:4444/grid/register

2. WebDriver

当Selenium2.x 提出了WebDriver的概念之后,它提供了完全另外的一种方式与浏览器交互。那就是利用浏览器原生的API,封装成一套更加面向对象的 Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的)。由于使用的是浏览器原生的API, 速度大大提高,而且调用的稳定性交给了浏览器厂商本身,显然是更加科学。然而带来的一些副作用就是,不同的浏览器厂商,对Web元素的操作和呈现多少会有 一些差异,这就直接导致了Selenium WebDriver要分浏览器厂商不同,而提供不同的实现。例如Firefox就有专门的FirefoxDriver,Chrome就有专门的 ChromeDriver等等。(甚至包括了AndroidDriver和iOS WebDriver)

引用一句个人赞同的原文:如果你使用的是WebDriver,你就可以直接抛弃Selenium Server。因为你根本不需要启动一个服务器来处理浏览器交互。

一个简答的使用WebDriver的例子:

    static{System.setProperty("webdriver.firefox.bin","C:/Program Files (x86)/Mozilla Firefox/firefox.exe");}
FirefoxDriver driver = new FirefoxDriver();
String url = "http://ap13933:8080";
driver.manage().window().setSize(new Dimension(1440,1000));
driver.get(url); WebElement name = driver.findElement(By.id("UserName"));
WebElement pwd = driver.findElement(By.id("OldPassword"));
while(!name.isDisplayed() || !pwd.isDisplayed())
sleep(100); name.clear();
pwd.clear();
name.sendKeys(username);
pwd.sendKeys(password);
pwd.submit();

WebDriver Wire协议是通用的,也就是说不管是FirefoxDriver还是ChromeDriver,启动之后都会在某一个端口启动基于这套协议的Web Service。例如FirefoxDriver初始化成功之后,默认会从http://localhost:7055开始,而ChromeDriver 则大概是http://localhost:46350之类的。接下来,我们调用WebDriver的任何API,都需要借助一个 ComandExecutor发送一个命令,实际上是一个HTTP request给监听端口上的Web Service。在我们的HTTP request的body中,会以WebDriver Wire协议规定的JSON格式的字符串来告诉Selenium我们希望浏览器接下来做社么事情。

在我们new一个WebDriver的过程中,Selenium首先会确认浏览器的native component是否存在可用而且版本匹配。接着就在目标浏览器里启动一整套Web Service,这套Web Service使用了Selenium自己设计定义的协议,名字叫做The WebDriver Wire Protocol。这套协议非常之强大,几乎可以操作浏览器做任何事情,包括打开、关闭、最大化、最小化、元素定位、元素点击、上传文件等等等等。

这里笔者初步画了一个图来表示各种WebDriver的工作原理:

从上图中我们可以看出,不同浏览器的WebDriver子类,都需要依赖特定的浏览器原生组件,例如Firefox就需要一个add- on名字叫webdriver.xpi。而IE的话就需要用到一个dll文件来转化Web Service的命令为浏览器native的调用。另外,图中还标明了WebDriver Wire协议是一套基于RESTful的web service。如果不明白什么是RESTful的,可以参见笔者之前另外一篇介绍REST的blog(http://blog.csdn.net/ant_yan/article/details/7963517)

关于WebDriver Wire协议的细节,比如希望了解这套Web Service能够做哪些事情,可以阅读Selenium官方的协议文档, 在Selenium的源码中,我们可以找到一个HttpCommandExecutor这个类,里面维护了一个Map<String, CommandInfo>,它负责将一个个代表命令的简单字符串key,转化为相应的URL,因为REST的理念是将所有的操作视作一个个状态,每 一个状态对应一个URI。所以当我们以特定的URL发送HTTP request给这个RESTful web service之后,它就能解析出需要执行的操作。截取一段源码如下:

    nameToUrl = ImmutableMap.<String, CommandInfo>builder()
.put(NEW_SESSION, post("/session"))
.put(QUIT, delete("/session/:sessionId"))
.put(GET_CURRENT_WINDOW_HANDLE, get("/session/:sessionId/window_handle"))
.put(GET_WINDOW_HANDLES, get("/session/:sessionId/window_handles"))
.put(GET, post("/session/:sessionId/url")) // The Alert API is still experimental and should not be used.
.put(GET_ALERT, get("/session/:sessionId/alert"))
.put(DISMISS_ALERT, post("/session/:sessionId/dismiss_alert"))
.put(ACCEPT_ALERT, post("/session/:sessionId/accept_alert"))
.put(GET_ALERT_TEXT, get("/session/:sessionId/alert_text"))
.put(SET_ALERT_VALUE, post("/session/:sessionId/alert_text"))

可以看到实际发送的URL都是相对路径,后缀多以/session/:sessionId开头,这也意味着WebDriver每次启动 浏览器都会分配一个独立的sessionId,多线程并行的时候彼此之间不会有冲突和干扰。例如我们最常用的一个WebDriver的 API,getWebElement在这里就会转化为/session/:sessionId/element这个URL,然后在发出的HTTP request body内再附上具体的参数比如by ID还是CSS还是Xpath,各自的值又是什么。收到并执行了这个操作之后,也会回复一个HTTP response。内容也是JSON,会返回找到的WebElement的各种细节,比如text、CSS selector、tag name、class name等等。以下是解析我们说的HTTP response的代码片段:

 
 
    try {
response = new JsonToBeanConverter().convert(Response.class, responseAsText);
} catch (ClassCastException e) {
if (responseAsText != null && "".equals(responseAsText)) {
// The remote server has died, but has already set some headers.
// Normally this occurs when the final window of the firefox driver
// is closed on OS X. Return null, as the return value _should_ be
// being ignored. This is not an elegant solution.
return null;
}
throw new WebDriverException("Cannot convert text to response: " + responseAsText, e);
} //...

相信总结道这里,应该对WebDriver的运行原理应该清楚了!其实挺佩服这一套RESTful web service的设计。感觉封装WebDriver暴露出来的public API还可以更加友好跟强大一点,这次就先总结道这里,会继续分析Selenium源码,继续分享的!

3. 使用selenium2.x的经验总结

其中WebDriver的更加面向对象的方式大大降低了Selenium的入门门槛,对Web元素的操作也非常之简单易 学。实际项目用起来,工作量最大的部分就是你如何解析定位到你的目标项目页面中的各种元素。好比你要定位一个Button,你可以用ID,可以用CSS, 可以用XPATH,你为了点击这个Button,写了一个函数调用Selenium里的API,即WebElement里的click()或者 submit(),那么另外一个Button怎么办?成百上千个Button又怎么办?

所以,你需要有一套自己实现的算法或者封装,来根据项目页面的特点提供一套通用的元素定位方式。当你的通用定位逻辑能准确 的找到任何一个元素的时候,剩下的事情就顺理成章了,交给Selenium WebElement的API就可以了。这一套定位逻辑笔者觉得才是使用Selenium做Web自动化工作量最大的部分。当然有的公司Web项目使用了 自己开发的UI框架,例如笔者所在的公司,这样Web元素的定位规则和算法就比较容易设计。如果Web项目开发出来的页面代码比较杂乱无章,那么你就需要 更加高明和严谨的逻辑去寻找你想要操作和查看的元素了!

在笔者的项目里,笔者自己设计并封装了一套通用的API,去智能的定位页面中的各种类型的元素。比如项目里的页面有大量的 dialog和wizard,都是用div+css实现的。我就提供了一个dialog组件,带有 next(),save(),finish(),click(String buttonName),cancel()等方法,然后根据遮罩层和loading Icon的时间来追踪操作完成的进度。这里只是举个小小的例子,有机会再分享更多的细节。

selenium及webdriver的原理的更多相关文章

  1. 【转】selenium及webdriver的原理

    主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://blog.csdn.net/ant_ren/article/det ...

  2. selenium及webdriver的原理【转】

    selenium与webdriver整合后,形成的新的测试工具叫做selenium2.x.在selenium1时间,selenium使用javascript来达到测试自动化的目标. 1. seleni ...

  3. Atitit WebDriver技术规范原理与概念

    Atitit WebDriver技术规范原理与概念 1. Book haosyo ma1 2. WebDriver是W3C的一个标准,由Selenium主持.1 3. WebDriver如何工作 (z ...

  4. Selenium:WebDriver简介及元素定位

    参考内容:官方API文档,下载链接:http://download.csdn.net/detail/kwgkwg001/4004500 虫师:<selenium2自动化测试实战-基于python ...

  5. selenium工作的大概原理

    selenium的原理是什么? selenium的原理涉及到3个部分,分别是 浏览器 driver: 一般我们都会下载driver client: 也就是我们写的代码 client其实并不知道浏览器是 ...

  6. selenium和webdriver区别

    接触selenium大概半年时间了.从开始的预研,简单的写个流程到后期的自动化框架的开发,因为本人不属于代码方面的大牛,一直的边研究边做.逐步深入学习.近期发现自己对本身selenium的发展还存在困 ...

  7. Selenium的webdriver的常用方法,鼠标事件

    就来认识 WebDriver 中最常用的几个方法: get():跳转到的地址clear(): 清除文本. send_keys (value): 模拟按键输入. click(): 单击元素. 示例: f ...

  8. selenium调用webdriver异常

    使用selenium调用webdriver的时候报错. from selenium import webdriver browser = webdriver.Chrome() browser.get( ...

  9. 第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例

    组合优点多,但经常比继承需要额外的代码. 上一篇是 介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的四种方式. 此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单, ...

随机推荐

  1. CSS之BFC及其应用

    BFC是Block Formatting Context的缩写,直译过来就是"块级格式化上下文".先不管它到底是什么,看一个例子: .parent{ border: 1px sol ...

  2. MyBatis3入门

    这里对mybatis的入门介绍以官方最新MyBatis3.4.1为准,具体文档及jar包请访问:https://github.com/mybatis/mybatis-3/releases. 以前经常都 ...

  3. struts2.1.6教程一、准备工作及实例

    1.解压struts-2.1.6-all.zip apps目录:struts2自带的例子程序 docs目录:官方文档. lib 目录:存放所有jar文件. Src 目录:源文%件存放地 2.六个基本包 ...

  4. UNIX文件I/O

    第一次用markdown语法写博客,写出来的还比较整齐,感觉博客园对序号的支持不是很好,调了一会才有了比较满意的效果,还有有哪位知道使用markdown如何插入frame? 这边博客主要说了APUE中 ...

  5. CentOS下SparkR安装部署:hadoop2.7.3+spark2.0.0+scale2.11.8+hive2.1.0

    注:之前本人写了一篇SparkR的安装部署文章:SparkR安装部署及数据分析实例,当时SparkR项目还没正式入主Spark,需要自己下载SparkR安装包,但现在spark已经支持R接口,so更新 ...

  6. Virtualbox让kali虚拟机共享主机的无线网络连接

    今天在测试虚拟机下安装kali系统时,遇到一个问题,默认安装完kali系统后,虚拟机不能上网.虚拟机网络配置使用的是默认的网络地址转换(NAT)选项. 网上查了很多,都说使用NAT模式时虚拟机不用做任 ...

  7. 浅谈JAVA验证码~

    这两天在帮同学做个项目,项目中需要做个验证码,说实话那么多年竟然没注意过这东西,原理很简单,贴出来给大家做个参考. 1.简单介绍 一般稍微有些经验的程序员都不会再自己写原生验证码生成了,因为各种强大的 ...

  8. DOM详解

    浏览器工作的基本流程 1.浏览器开始解析html文档,构建DOM树(DOM tree),DOM树的节点由文档的标签.属性.文本等组成:2.解析外部CSS文件及style标签中的样式信息,这些样式信息将 ...

  9. redis集群搭建实践

    参考 第一个节点 第一个节点为本地的机器 IP:192.168.23.148 检查机器配置 $ uname -a Linux wangya-Lenovo-G480 4.8.0-52-generic # ...

  10. SQL数据库的多表查询

    多表查询分为 内.外连接 外连接分为左连接(left join 或left outer join).右连接(right join 或者 right outer join).和完整外部连接 (full ...