Selenium 2.0的由来及设计架构(三)

上一篇 / 下一篇  2013-08-17 20:24:41 / 个人分类:功能自动化

接着上一篇继续介绍Remote DriverFirefox Driver

远程Webdriver协议的第二次迭代因此使用了HTTP传输机制和UTF-8编码的JSON作为默认的编码,使客户端可以很容易的使用各种有限支持Unicode的语言,因为UTF-8向后兼容ASCII。发送给服务器的命令使用URL以确定哪个命令被发送,并编码在一个数组中的命令的参数。

例如,一个命令WebDriver.get("http://www.example.com")映射到一个到URLPOST请求,编码了回话ID和以/结束,使用像{[}'http://www.example.com'{]}这样的参数的阵列。返回的结果更有结构性,有一个返回值和错误码的代码占位。不久到了第三次远程协议迭代,使用命名参数字典取代了参数请求数组。这有利于更方便的调试请求,消除了客户端失误使用了参数的可能性,使得系统更健壮。当然,决定使用正常的HTTP错误码表示确定的返回值和响应,例如,如果用户试图调用一个没有映射到的URL,或者当我们想表示空响应时,这是种最合适的方式。

Webdriver远程协议有两个错误处理层次,一个无效的请求和一个失败的命令。无效的请求的例子是请求一个服务器并不存在的资源,或者可能是资源不理解,(例如发送一个DELETE命令给用于处理当前页面的URL的资源)。这种情况下,一个正常的HTTP响应是4XX。对于失败的命令,错误码设置为500(服务器端错误),并且返回的数据包含更详细的错误分解。

当包含数据的响应从服务器发出后,它是一个JSON对象的格式:

Key                   描述

Sessionid   服务器使用的决定何处路由特定会话命令的不透明处理

状态值     一个概括命令结果数字状态码,非零值代表命令失败响应的JSON

例如:

FirefoxDriver.prototype.getElementAttribute = 
function(respond, parameters) { 
    var element = Utils.getElementAt(parameters.id, respond.session.getDocument()); 
    var attributeName = parameters.name; 
    respond.value = webdriver.element.getAttribute(element, attributeName); 
    respond.send(); 
};

因为可见,我们会在响应中编码状态码,使用非零值表示发生了糟糕的事故。首先在IE driver上使用了状态码,而且被用于了线协议。因为所有的错误码在不同的driver中一致的,在不同的driver中可以使用特殊的语言完成共享错误处理的代码,使客户端更容易实现。

远程webdriver服务简单讲是一个Java servlet,扮演多重角色,路由收到的所有的命令给对应的Webdriver实例。诸如此类的事情,一个大二的学生都能完成。Firefox driver也完成了远程Webdriver协议,它的架构更加有趣,所以让我们跟踪一个从语言绑定的会话到后端一直到返回给用户的请求。

假设我们使用JAVAelement就是WebElement的一个实例,这样开始:

element.getAttribute("row");

在内部,元素有一个透明的ID,服务器用于识别是哪一个元素。为了便于讨论,我们假设这个ID有一个值some_opaque_id,被加密成JAVA命令对象,使用MAP映射到一个参数IDname,表示用于要查询的属性名的元素IDname

快速看一下正确的URL是:

/session/:sessionId/element/:id/attribute/:name

以冒号开始的URL的任何部分假定是一个需要被替换的变量,我们已经获得IDname,当一个服务器可以同时处理多个会话(Firefox driver不能)时,那么sessionId是另一种用于路由功能的不透明的句柄,这个URL因此像这样扩展:

http://localhost:7055/hub/session/XXX/element/some_opaque_id/attribute/row

顺便说一句,webdriver的远程线协议最初是在与URL模板草案提出时同时开发的,我们以明确URLURL模板的方案允许在一个URL里进行变量扩展(派生)。遗憾的是,虽然URL模板同时提出,我们只意识到他们相对晚了一天,因此他们不会被用作设计线协议。

因为我们正执行的方法是idempotent4,正确的HTTP方法是使用get,我们委托一个能处理HTTPApacheHTTP客户端)来调用服务器的Java库。

Firefox driver被实现成一个Firefox扩展,它的基本设计如上图所示。有些不同寻常的是,它有一个嵌入式HTTP服务器,虽然最初我们使用我们自己创建的,在XPCOM上写的HTTP服务器并不是我们的核心竞争力之一,所以机会出现时,我们使用基本的由Mozilla自己写的HTTPD取代了它,HTTPD收到请求马上传递给调度对象。

调度器接收请求并遍历一个已知支持的URL列表,尝试找到相匹配的请求,这种匹配完成了在客户端上的变量插值,一旦精确匹配到,包括使用的动作,JSON对象,就意味着在构造要执行的命令。我们的案例中看起来像:

{

  'name': 'getElementAttribute',

  'sessionId': { 'value': 'XXX' },

  'parameters': {

    'id': 'some_opaque_key',

    'name': 'rows'

  }

然后将其作为一个JSON字符串传递到一个自定义的XPCOM组件中,我们叫它CommandProcessor

var jsonResponseString = JSON.stringify(json);

var callback = function(jsonResponseString) {

  var jsonResponse = JSON.parse(jsonResponseString);


  if (jsonResponse.status != ErrorCode.SUCCESS) {

    response.setStatus(Response.INTERNAL_ERROR);

  }

  response.setContentType('application/json');

  response.setBody(jsonResponseString);

  response.commit();

};

// Dispatch the command.

Components.classes['@googlecode.com/webdriver/command-processor;1'].

    getService(Components.interfaces.nsICommandProcessor).

    execute(jsonString, callback);

这里有大量的代码,但是有两个关键点。首先,我们把上面的对象转换成JSON字符串,其次传递一个回调的执行方法来发送HTTP响应。

未完待续,请阅读后面的文章

Selenium 2.0的由来及设计架构(四)

本文是译文,原文请参考:http://www.aosabook.org/en/selenium.html

===========================

关注微信zzzmmmkkk,不定期吐槽有关测试技术,测试经验,测试思考和生活感悟等。


TAG: Driver 设计架构 firefox FireFox Firefox webdriver WebDriver

 

评分:0

我来说两句

Open Toolbar