测试工具工作原理.doc_第1页
测试工具工作原理.doc_第2页
测试工具工作原理.doc_第3页
测试工具工作原理.doc_第4页
测试工具工作原理.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Selenium 工作原理selenium 是thoughtWorks公司的一个强大的开源Web功能测试工具系列,采用javascript来管理整个测试过程,包括读入测试套件,执行测试和记录测试结果。它采用javascript单元测试工具JSUnit为核心,模拟正式用户操作,包括浏览页面,点击链接,输入文字,提交表单,触发鼠标事件等。并且能够对页面结果进行种种验证。也就是说,只要在测试用例中把预期的用户行为与结果都描述出来,我们就得到了一个可以自动化运行的功能测试套件。Selenium的核心是用javascript写的,他和浏览器进行通行,把测试用例的信息发送给浏览器执行,从而达到自动化测试的目的通过研究selenium-webdriver的源码,笔者发现其实webdriver的实现原理并不高深莫测无法揣度。在这里以webdriver ruby binding的firefox-webdriver实现为例,简单介绍一下webdriver的工作原理。 当测试脚本启动firefox的时候,selenium-webdriver 会首先在新线程中启动firefox浏览器。如果测试脚本指定了firefox的profile,那么就以该profile启动,否则的话就新启1个profile,并启动firefox; firefox一般是以-no-remote的方法启动,启动后selenium-webdriver会将firefox绑定到特定的端口,绑定完成后该firefox实例便作为webdriver的remote server存在; 客户端(也就是测试脚本)创建1个session,在该session中通过http请求向remote server发送restful的请求,remote server解析请求,完成相应操作并返回response; 客户端接受response,并分析其返回值以决定是转到第3步还是结束脚本;这就是webdriver的工作流程,看起来很复杂实际上当了解了webdriver的实现原理后,理解上述问题应该比较简单。webdriver是按照server client的经典设计模式设计的。server端就是remote server,可以是任意的浏览器。当我们的脚本启动浏览器后,该浏览器就是remote server,它的职责就是等待client发送请求并做出相应;client端简单说来就是我们的测试代码,我们测试代码中的一些行为,比如打开浏览器,转跳到特定的url等操作是以http请求的方式发送给被 测试浏览器,也就是remote server;remote server接受请求,并执行相应操作,并在response中返回执行状态、返回值等信息;举个实际的例子,下面代码的作用是”命令”firefox转跳到google主页:driver = Selenium:WebDriver.for :firefoxdriver.navigate.to 在执行driver.navigate.to “” 这句代码时,client,也就是我们的测试代码向remote server发送了如下的请求:POST session/285b12e4-2b8a-4fe6-90e1-c35cba245956/urlpost_data url: 通过post的方式请求localhost:port/hub/session/session_id/url地址,请求浏览器完成跳转url的操作。如果上述请求是可接受的,或者说remote server是实现了这个接口,那么remote server会跳转到该post data包含的url,并返回如下的responsename:get,sessionId:285b12e4-2b8a-4fe6-90e1-c35cba245956,status:0,value:该response中包含如下信息 name:remote server端的实现的方法的名称,这里是get,表示跳转到指定url; sessionId:当前session的id; status:请求执行的状态码,非0表示未正确执行,这里是0,表示一切ok不许担心; value:请求的返回值,这里返回值为空,如果client调用title接口,则该值应该是当前页面的title;如果client发送的请求是定位某个特定的页面元素,则response的返回值可能是这样的:name:findElement,sessionId:285b12e4-2b8a-4fe6-90e1-c35cba245956,status:0,value:ELEMENT:2192893e-f260-44c4-bdf6-7aad3c919739name,sessionId,status跟上面的例子是差不多的,区别是该请求的返回值是ELEMENT:2192893e- f260-44c4-bdf6-7aad3c919739,表示定位到元素的id,通过该id,client可以发送如click之类的请求与 server端进行交互。那么remote server端的这些功能是如何实现的呢?答案是浏览器实现了webdriver的统一接口,这样client就可以通过统一的restful的接口去进 行浏览器的自动化操作。目前webdriver支持ie, chrome, firefox, opera等主流浏览器,其主要原因是这些浏览器实现了webdriver约定的各种接口webdriver原理:1. WebDriver 启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,做为web driver的remote server。2. Client 端通过CommandExcuter 发送HTTPRequest 给remote server 的侦听端口(通信协议: the webriver wire protocol)3. Remote server 需要依赖原生的浏览器组件(如:IEDriver.dll,chromedriver.exe),来转化转化浏览器的native调用。查看命令提示符下的运行日志:咋一看很乱,慢慢分析一下就发现很有意思!结合上面的脚本分析-启动代理进入监听状态C:seleniumjava -jar selenium-server-standalone-2.33.0.jar八月 22, 2013 10:19:48 上午 org.openqa.grid.selenium.GridLauncher mainINFO: Launching a standalone server10:19:48.734 INFO - Java: Oracle Corporation 23.21-b0110:19:48.734 INFO - OS: Windows XP 5.1 x8610:19:48.734 INFO - v2.33.0, with Core v2.33.0. Built from revision 4e90c9710:19:48.843 INFO - RemoteWebDriver instances should connect to: :4444/wd/hub10:19:48.843 INFO - Version Jetty/5.1.x10:19:48.843 INFO - Started HttpContext/selenium-server/driver,/selenium-server/driver10:19:48.843 INFO - Started HttpContext/selenium-server,/selenium-server10:19:48.843 INFO - Started HttpContext/,/10:19:48.890 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler176343e10:19:48.890 INFO - Started HttpContext/wd,/wd10:19:48.906 INFO - Started SocketListener on :444410:19:48.906 INFO - Started org.openqa.jetty.jetty.Server388c74-创建新session 10:20:38.593 INFO - Executing: new session: platform=ANY, javascriptEnabled=true, browserName=chrome, version= at URL: /session)10:20:38.593 INFO - Creating a new session for Capabilities platform=ANY, javascriptEnabled=true, browserName=chrome, version= webdrivr通过GET方式发送请求0.921INFO: received Webriver request: GET /status 向webdrver返回响应,返回码200表示成功0.921INFO: sending Webriver response: 200 sessionId: , status: 0, value: build: version: alpha , os: arch: x86, name: Windows NT, version: 5.1 SP3 webdriver 再次以POST方式发送请求,并启动浏览器相关信息0.984INFO: received Webriver request: POST /session desiredCapabilities: browserName: chrome, javascriptEnabled: true, platform: ANY, version: 0.984INFO: Launching chrome: C:ocuments and SettingsAdministratorLocal SettingsApplication ataGoogleChromeApplicationchrome.exe -remote-debugging-port=4223 -no-first-run -enable-logging -logging-level=1 -user-data-dir=C:OCUME1AMINI1LOCALS1Tempscoped_dir1808_7550 -load-extension=C:OCUME1AMINI1LOCALS1Tempscoped_dir1808_26821internal -ignore-certificate-errors data:text/html;charset=utf-8,1.773INFO: sending Webriver response: 303webdriver再次以GET方法请求,这附加上了session的信息1.778INFO: received Webriver request: GET /session/32b33aa585ccbbf7ba78535882852af3服务器先对sesssionID进行解析,确认是selenium调用的以及要访问的网址,1.779INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: acceptSslCerts: true, applicationCacheEnabled: false, browserConnectionEnabled: false, browserName: chrome, chrome: chromedriverVersion: 2.0 , cssSelectorsEnabled: true, databaseEnabled: true, handlesAlerts: true, javascriptEnabled: true, locationContextEnabled: true, nativeEvents: true, platform: Windows NT, rotatable: false, takesScreenshot: true, version: 27.0.1453.116, webStorageEnabled: true 10:20:40.640 INFO - Done: /session10:20:40.640 INFO - Executing: org.openqa.selenium.remote.server.handler.GetSessionCapabilities14cf7a1 at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc)10:20:40.640 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc10:20:40.656 INFO - Executing: get: at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/url)webdriver正试向服务器请求youdao网站1.820INFO: received Webriver request: POST /session/32b33aa585ccbbf7ba78535882852af3/url url: 1.822INFO: waiting for pending navigations.1.829INFO: done waiting for pending navigations2.073INFO: waiting for pending navigations.2.900INFO: done waiting for pending navigations获得服务器数据的应答2.900INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: null10:20:41.734 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/url-下面接着发送定位输入框的信息10:20:41.734 INFO - Executing: find element: B: q at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element)2.905INFO: received Webriver request: POST /session/32b33aa585ccbbf7ba78535882852af3/element using: name, value: q2.905INFO: waiting for pending navigations.2.905INFO: done waiting for pending navigations2.922INFO: waiting for pending navigations.2.922INFO: done waiting for pending navigations得到服务器应答2.922INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: ELEMENT: 0.19427558477036655:1 10:20:41.765 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element10:20:41.765 INFO - Executing: send keys: 0 org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElementa8215ba9, h, e, l, l, o at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value)向定位到的输入框写入hello2.936INFO: received Webriver request: POST /session/32b33aa585ccbbf7ba78535882852af3/element/0.19427558477036655:1/value id: 0.19427558477036655:1, value: h, e, l, l, o 2.936INFO: waiting for pending navigations.2.936INFO: done waiting for pending navigations3.002INFO: waiting for pending navigations.3.002INFO: done waiting for pending navigations3.002INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: null10:20:41.843 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value再次发送定位输入框的请求10:20:41.843 INFO - Executing: find element: B: q at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element)3.006INFO: received Webriver request: POST /session/32b33aa585ccbbf7ba78535882852af3/element using: name, value: q3.006INFO: waiting for pending navigations.3.006INFO: done waiting for pending navigations3.016INFO: waiting for pending navigations.3.016INFO: done waiting for pending navigations3.016INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: ELEMENT: 0.19427558477036655:1 10:20:41.859 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element10:20:41.859 INFO - Executing: send keys: 0 org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElementa8215ba9, k, e, y, ., E, N, T, E, R at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value)对定位的到的输入框发送回车(ENTER)事件请求3.021INFO: received Webriver request: POST /session/32b33aa585ccbbf7ba78535882852af3/element/0.19427558477036655:1/value id: 0.19427558477036655:1, value: k, e, y, ., E, N, T, E, R 3.021INFO: waiting for pending navigations.3.021INFO: done waiting for pending navigations3.064INFO: waiting for pending navigations.3.064INFO: done waiting for pending navigations3.064INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: null10:20:41.906 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value10:20:41.906 INFO - Executing: close window at URL: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/window)3.068INFO: received Webriver request: ELETE /session/32b33aa585ccbbf7ba78535882852af3/windowWARNING:chrome_desktop_impl.cc(88) chrome detaches, user should take care of directory:C:DOCUME1ADMINI1LOCALS1Tempscoped_dir1808_7550 and C:DOCUME1ADMINI1LOCALS1Tempscoped_dir1808_268215.318INFO: sending Webriver response: 200 sessionId: 32b33aa585ccbbf7ba78535882852af3, status: 0, value: null10:20:44.156 INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/windowrequest 请求 / response 应答一次请求会对应一次应答POST/GET 是请求(request)两种类型;关于两种请求方式的类别参考其它资料200 、203 是 HTTP请求返回的状态码,200表示成功;sessionid :每一个访问服务器的客户端,都要先得到服务器端分配的一个sessionid ,就像通行证一样,只有得到sessionid的客户端才能向服务器请求想要的数据。其它还包括操作系统版本,浏览器类型、URL、字符类型等非常详细的记录。熟悉HTTP ,了解TCP 的三次握手四次挥手,相信你对浏览器的交互与webdriver原理会有更深入的认识。最近比较空闲就仔细看了一下Selenium的源码,因为主要是使用WebDriver所以重点关注了一下WebDriver的工作原理。在前一篇blog里已经解释过了WebDriver与之前Selenium的JS注入实现不同,直接利用了浏览器native support来操作浏览器。所以对于不同平台,不同的浏览器,必须依赖一个特定的浏览器的native component来实现把WebDriver API的调用转化为浏览器的native invoke。t(pB;k!Z4K+g Ch0mEnmp051Testing软件测试网;na f o|X51Testing软件测试网pLSaso e$K51Testing软件测试网2jVnj.r#s4M在我们new一个WebDriver的过程中,Selenium首先会确认浏览器的native component是否存在可用而且版本匹配。接着就在目标浏览器里启动一整套Web Service,这套Web Service使用了Selenium自己设计定义的协议,名字叫做The WebDriver Wire Protocol。这套协议非常之强大,几乎可以操作浏览器做任何事情,包括打开、关闭、最大化、最小化、元素定位、元素点击、上传文件等等等等。c_fQ4S?!IBU051Testing软件测试网ia5HZ)Wo251Testing软件测试网$X$AE%ia,y6XY4#R m w*f*C2L051Testing软件测试网+Y&Px5S-&CMWebDriver 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我们希望浏览器接下来做社么事情。51Testing软件测试网8c+M6J9|+K51Testing软件测试网2L(F7?-Q i51Testing软件测试网XOVfP 5m5vAV/_k+xcn051Testing软件测试网5H1KI.E6tgz这里笔者初步画了一个图来表示各种WebDriver的工作原理:8q/GJn+?j*Pl:_2a/Ai051Testing软件测试网lg+Y(DE|e/CK3s,uu0rV#|1u)Q0_CO0Zdzv;h!_&F0+WL&RpR,051Testing软件测试网N;K|U4 D+_2YXi(|tW Tk05FN sM*h)YJ4h013/OSJs0P!u1GM6JA WN0从上图中我们可以看出,不同浏览器的WebDriver子类,都需要依赖特定的浏览器原生组件,例如Firefox就需要一个add-on名字叫webdriver.xpi。而IE的话就需要用到一个dll文件来转化Web Service的命令为浏览器native的调用。另外,图中还标明了WebDriver Wire协议是一套基于RESTful的web service。如果不明白什么是RESTful的,可以参见笔者之前另外一篇介绍REST的blog(/ant_yan/article/details/7963517)51Testing软件测试网.g+id6hh.e2bl51Testing软件测试网jWb$XI&u5qozd2V2Od3vu0(Y(N*k:e03S:.d&_ vV%C0关于WebDriver Wire协议的细节,比如希望了解这套Web Service能够做哪些事情,可以阅读Selenium官方的协议文档, 在Selenium的源码中,我们可以找到一个HttpCommandExecutor这个类,里面维护了一个Map,它负责将一个个代表命令的简单字符串key,转化为相应的URL,因为REST的理念是将所有的操作视作一个个状态,每一个状态对应一个URI。所以当我们以特定的URL发送HTTP request给这个RESTful web service之后,它就能解析出需要执行的操作。截取一段源码如下:xC f3|k)M0J051Testing软件测试网x1Ev6.PV!B(j#v&E/h0javaview plaincopyprint?1. nameToUrl = ImmutableMap.builder() 2. .put(NEW_SESSION, post(/session) 3. .put(QUIT, delete(/session/:sessionId) 4. .put(GET_CURRENT_WINDOW_HANDLE, get(/session/:sessionId/window_handle) 5. .put(GET_WINDOW_HANDLES, get(/session/:sessionId/window_handles) 6. .put(GET, post(/session/:sessionId/url) 7.8. / The Alert API is still experimental and should not be used. 9. .put(GET_ALERT, get(/session/:sessionId/alert) 10. .put(DISMISS_ALERT, post(/session/:sessionId/dismiss_alert) 11. .put(ACCEPT_ALERT, post(/session/:sessionId/accept_alert) 12. .put(GET_ALERT_TEXT, get(/session/:sessionId/alert_text) 13. .put(SET_ALERT_VALUE, post(/session/:sessionId/alert_text) nameToUrl = ImmutableMap.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)51Testing软件测试网#zcYj1x*i.X7X4UN#J 0可以看到实际发送的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的代码片段:51Testing软件测试网4YI,T8Oo Q&jx|7YRx*B051Testing软件测试网5nPUI4A/o(Vt6X+xH;l1|w L$0_2/VU!C/tZ$V051Testing软件测试网 Wv|Mk&O:Xjavaview plaincopyprint?1. try 2. response = new JsonToBeanConverter().convert(Response.class, responseAsText); 3. catch (ClassCastException e) 4. if (responseAsText != null & .equals(responseAsText) 5. / The remote server has died, but has already set some headers. 6. / Normally this occurs when the final window of the firefox driver 7. / is closed on OS X. Return null, as the return value _should_ be 8. / being ignored. This is not an elegant solution. 9. return null; 10. 11. throw new WebDriverException(Cannot convert text to response: + responseAsText, e); 12. /. 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); /.51Testing软件测试网1o._4QF%Z Y相信总结道这里,应该对WebDriver的运行原理应该清楚了!其实挺佩服这一套RESTful web service的设计。感觉封装WebDriver暴露出来的public API还可以更加友好跟强大一点,这次就先总结道这里,会继续分析Selenium源码,继续分享的!Loadrunner工作原理对于lr的原理,我想应该和其它性能测试工具的原理是一样的。一般来说,性能测试工具都有一个虚拟用户脚本产生器(vugen),压力产生器和用户代理、压力调度和监控系统、压力结果分析工具对于虚拟用户产生器来讲,主要的功能就是通过代理接收从客户端发送的数据包,记录并转发给服务器,接收服务器端的数据包,记录并转发给客户端。除此之外,虚拟用户脚本生成器在截获数据之后,根据录制时使用的协议对数据包分析,用脚本函数记录下来。并提供了编译和调试的环境,用于对脚本的优化和修改压力产生器用于根据压力调度系统的命令,产生实际的负载压力调度和监控系统:压力调度工具可以根据用户的场景要求,设置不同的Vu数量等 监控系统主要是用于对数据库、服务器的性能计数器等的监控压力结果分析工具 主要是将获取的性能计数器的信息,生成相应的分析图一、 LoadRunner工具组成1、虚拟用户脚本生成器:捕获最终用户业务流程和创建自动性能测试脚本,即我们在以后说的产生测试脚本;2、压力产生器:通过运行虚拟用户产生实际的负载;3、用户代理:协调不同负载机上虚拟用户,产生步调一致的虚拟用户;4、压力调度:根据用户对场景的设置,设置不同脚本的虚拟用户数量;5、监视系统:监控主要的性能计数器;6、压力结果分析工具:本身不能代替分析人员,但是可以辅助测试结果的分析。二、 LoadRunner工具原理代理(Proxy)是客户端和服务器端之间的中介人,LoadRunner就是通过代理方式截获客户端和服务器之间交互的数据流。1、虚拟用户脚本生成器通过代理方式接收客户端发送的数据包,记录并将其转发给服务器端;接收到从服务器端返回的数据流,记录并返回给客户端。这样服务器端和客户端都以为在一个真实运行环境中,虚拟脚本生成器能通过这种方式截获数据流;虚拟用户脚本生成器在截获数据流后对其进行了协议层上的处理,最终用脚本函数将数据流交互过程体现为我们容易看懂的脚本语句。2、压力生成器则是根据脚本内容,产生实际

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论