selenium及webdriver的原理
主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://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至今为止还保留着,应该是考虑到向前兼容吧,命令如下:
- java -jar selenium-server-standalone-2.14.0.jar -role hub
- 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的原理的更多相关文章
- 【转】selenium及webdriver的原理
主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://blog.csdn.net/ant_ren/article/det ...
- selenium及webdriver的原理【转】
selenium与webdriver整合后,形成的新的测试工具叫做selenium2.x.在selenium1时间,selenium使用javascript来达到测试自动化的目标. 1. seleni ...
- Atitit WebDriver技术规范原理与概念
Atitit WebDriver技术规范原理与概念 1. Book haosyo ma1 2. WebDriver是W3C的一个标准,由Selenium主持.1 3. WebDriver如何工作 (z ...
- Selenium:WebDriver简介及元素定位
参考内容:官方API文档,下载链接:http://download.csdn.net/detail/kwgkwg001/4004500 虫师:<selenium2自动化测试实战-基于python ...
- selenium工作的大概原理
selenium的原理是什么? selenium的原理涉及到3个部分,分别是 浏览器 driver: 一般我们都会下载driver client: 也就是我们写的代码 client其实并不知道浏览器是 ...
- selenium和webdriver区别
接触selenium大概半年时间了.从开始的预研,简单的写个流程到后期的自动化框架的开发,因为本人不属于代码方面的大牛,一直的边研究边做.逐步深入学习.近期发现自己对本身selenium的发展还存在困 ...
- Selenium的webdriver的常用方法,鼠标事件
就来认识 WebDriver 中最常用的几个方法: get():跳转到的地址clear(): 清除文本. send_keys (value): 模拟按键输入. click(): 单击元素. 示例: f ...
- selenium调用webdriver异常
使用selenium调用webdriver的时候报错. from selenium import webdriver browser = webdriver.Chrome() browser.get( ...
- 第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例
组合优点多,但经常比继承需要额外的代码. 上一篇是 介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的四种方式. 此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单, ...
随机推荐
- BM25和Lucene Default Similarity比较 (原文标题:BM25 vs Lucene Default Similarity)
原文链接: https://www.elastic.co/blog/found-bm-vs-lucene-default-similarity 原文 By Konrad Beiske 翻译 By 高家 ...
- DelayQueue的原理和使用浅谈
在谈到DelayQueue的使用和原理的时候,我们首先介绍一下DelayQueue,DelayQueue是一个无界阻塞队列,只有在延迟期满时才能从中提取元素.该队列的头部是延迟期满后保存时间最长的De ...
- Java 7 Fork/Join 框架
在 Java7引入的诸多新特性中,Fork/Join 框架无疑是重要的一项.JSR166旨在标准化一个实质上可扩展的框架,以将并行计算的通用工具类组织成一个类似java.util中Collection ...
- 桥梁模式(Bridge Pattern)
桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation) ...
- o(n)线性排序算法
O(n) 排序算法 前言 前面有总结过各类常用的排序算法,但是那些排序算法最优的时间复杂度是O(nlogn),所以我要介绍三种时间复杂度为O(n)的线性时间复杂度的排序算法. 计数排序 计数排序利用了 ...
- springMvc注解之@ResponseBody和@RequestBody
简介 springmvc对json的前后台传输做了很好封装,避免了重复编码的过程,下面来看看常用的@ResponseBody和@RequestBody注解 添加依赖 springmvc对json的处理 ...
- 使用 CKEditor 上传图片, 粘贴屏幕截图
之前写过wangEditor,那真是好用,文档也清晰,半天就搞定了,无奈没有对应license,只好选择别的. 外语一般,阅读理解都靠蒙.CKEditor官方文档看的我云里雾里,国内的博客比较少,经过 ...
- XD
题目 是否完成 题目分类 简要题解 没有上司的舞会(codevs1380) Y 树形dp dp[u][0]表示不包含此节点,dp[u][1]表示包含,转移方程为 dp[u][0]+=max(dp[v] ...
- Iterator(es6)
1.任何数据结构只要部署了Iterator接口(本质是一个指针对象),也就是部署了Symbol.iterator属性,便可以完成遍历操作:数组原生就具备Iterator接口,就可以用for...of遍 ...
- IIS的安装与设置(windows版本)
IIS,全英文名称:Internet Information Services(互联网信息服务),是由微软公司提供的基于运行Microsoft Windows的互联网基本服务.IIS的功能很多,如编辑 ...