少欲无为,身心自在。得失从缘,心无增减。

发布新日志

  • Selenium UI Element学习笔记(四)

    2009-09-18 16:39:33

    Selenium UI Element实战篇
        
         至此已经介绍完了UI Element的Map文件的全部内容。接下来就是真正在Selenium中应用它
    了。之前说过,UI Element是可以在Selenium IDE和RC中共用的。它的确为统一识别和维护网页
    对象提供了标准的处理方式。下面逐一介绍。    
         Selenium IDE
          在IDE中,要想使这些辛辛苦苦编写好的映射文件起作用还需要一些设置。这个映射文件是
    一个js文件。

    1. FirfeFox中打开Selenium IDE界面,在主菜单的options中选择Option...菜单项
    2. 在General标签页面中, 设置Selenium Core extensions为包含此js文件的路径
    3. 重启Firfox,使设置生效     

         Selenium RC
        
    在RC中,你有两种方式可以选择
    • 在RC的启动脚本中增加-userExtensions参数指定js文件
    启动Selenium服务器的脚本命令参考: java -jar selenium-server.jar
    [-interactive] [options]

    • -port <nnnn>: selenium 服务器使用的端口号(默认4444)
    • -timeout <nnnn>: 我们放弃前(超时)所等待的秒数
    • -interactive: 进入交互模式。参考教程获取更多信息
    • -multiWindow: 进入被测试网站都在单独窗口打开的模式,并且
    selenium支持frame

    • -forcedBrowserMode <browser>: 设置浏览器模式(例如,所有的会
    话都使用"*iexplore",不管给
    getNewBrowserSession 传递什么参数)
    • -userExtensions <file>: 指定一个被载入到selenium 的
    JavaScript. 文件

    • -browserSessionReuse: 停止在测试间重新初始化和替换浏览器。
    • -alwaysProxy: 默认情况下,我们尽量少的进行代理;设置这个标志
    将会强制所有的浏览器通讯都通过代理

    • -firefoxProfileTemplate <dir>: 一般情况,我们在每次启动之前
    都生成一个干净的Firefox 设置。您可以指定一个目

    录来让我们将您的设置拷贝过来,代替我们生成的。
    • 在编程IDE的代码文件中使用DefaultSelenium类的setUserExtensionJs(fileName)
      方法动态指定js文件。
        
         终于,Selenium UI Element的学习告一段落。先休息会,接下来就要好好应用了。待应
    用一段时间后,再来写体会,哈哈哈~
  • Selenium UI Element学习笔记(三)

    2009-09-18 14:41:36

    Selenium UI Element高级应用篇

         这次是高级应用篇了,读完这些,我发现利用UI Element能帮我处理掉大部分的对象识别问
    题了,这里将映射技术发挥得淋漓尽致。TestCompelte中的别名映射机制与它相比...唉,真是不
    好比啊~

         Testcases

         这里的testcase是用来验证Selenium能正确地按照Locator设置的路径来识别对象的。
    Selenium会统计失败的测试用例的情况。编写这样的测试用例的另一个目的则是可以直观地表现
    最终可能出现的对象路径。
         一个Testcases会是这样编写的
    testcase1: {
    args: { line: 2, column: 3 }
    , xhtml: '<table id="scorecard">'
    + '<tr class="line" />'
    + '<tr class="line"><td /><td /><td expected-
    result="1" /></tr>'
    + '</table>'
    }

    解析:
    一个testcase对象中有两个必要的属性,args(数组对象)和xhtml(String)。
    agrs属性的对象会被传递给UI Element的getLocator函数。它用来生成test locator,
    这个locator由xhtml语句描述。若这个Locator返回了期望的值,那么这个测试就被认为
    是通过的。xhtml属性必须用xhuml语言描述,不需要<html>标签,这会自动加上。这么做
    是为了能让Firfox的XML解析器正确解读。不幸地是不能生成HTML文档,只能生成XML文档。
    这就要求区分大小写,即所有的tag名都必须小写。


    模糊匹配

    实际的网页中,往往会看到这样的代码结构

    <table>
    <tr nclick="showDetails(0)">
    <td>Brahms</td>
    <td>Viola Quintet</td>
    </tr>
    <tr nclick="showDetails(1)">
    <td>Saegusa</td>
    <td>Cello 88</td>
    </tr>
    </table>

    想象一下,我在录制脚本。我想点击Cello 88这个按钮。IDE会为我创建这样一个Locator
    ://table/tr[2]/td[2]。这是否就意味这我的getLocator函数就会返回一个同样的
    Xpath吗?显然不是。点击这个表格的第二行中的人一个按钮都是同样的结果。我的UI
    Element的XPath很可能是
    这样的:
    //table/tr[2]。在录制的时候,作为点击动作的页面对象在层级结构的上一层
    (即TD标签而不是TR),这就不能和我的UI Elment Xpath匹配了。那么该怎么解决这个问
    题呢?

    Fuzzy matching!
    什么是Fuzzy Matching?
    它是一个函数,若一个Dom Elemnt目标可以被认为相当于另一个DOM Element的参照物(
    由Xpath生成)时,此函数返回True。一般而言,它的匹配规则是这样的:
    • 有多个相同的element
    • 参考element是唯一的,而目标element是它的后代
    • 参考element有一个onclik属性,而目标element是它的后代 
    这样的逻辑或许不一定适合你。幸运地是你可以修改它,在ui element.js文件中,
    你可以查看一下BrowserBot.prototype.locateElementByUIElement
    .is_fuzzy_match的定义。

    辅助定位器()

    辅助定位器是一种附加在UI Special String后面形成的一种组合定位模式。它们可以通过
    IDE录制器自动生成getOffsetLocator函数。
    当你需要将页面上大量的内容定义成UI
    Element时,
    这一特性也许非常有用,它可以用来简化代码。这种情况下,它允许你定义一个
    可以包含固定的其他的要素的UI Element。来看一例子感受一下吧
    假设有这样一段页面元素
    <form. name="contact_info">
    <input type="text" name="foo" />
    <textarea name="bar"></textarea>
    <input type="submit" value="baz" />
    </form>


    应用map时的对象引用写法如下
    ui=contactPages::contact_form()->//input[@name='foo']
    ui=contactPages::contact_form()->//textarea[@name='bar']
    ui=contactPages::contact_form()->//input[@value='baz']


    解析:
    录制时,系统将采用UIElement.defaultOffsetLocatorStrategy来自动生成对象
    代码。“->”符号用来界定根据何种固定要素来识别相似的Page Element。因此,这个符号
    不能在主要的定位器或任何可能产生意外结果的地方中使用。需要注意的是这中定位方式只适
    用于Xpath,其他定位方式以后或许也会提供相似的支持。


    Rollup Rules

    Rollup就是一组常用Selenium命令的组合体。UI Eleemnt的设计目标是使IDE中编写可以
    简单而轻松地编写测试代码,当然它缺少一些重要的编程特性(比如IF、While、Function
    )。这必然令你倾向于使用Selenium RC编写测试代码。另一种选择,就是Rollup Rule。
    通过Selenium的testruuner生成的组件命令执行rollup命令会表现得像在调用函数一样
    简单。这些rollup的扩展可在javascript中编写。因此,这样rule可以作为一个user
    extension加入到任何一款Selenium家族产品中。尤其突出的一点是,
    在理解了命令怎
    样扩展成rollup和roullup rules怎样被拆解成rollup命令
    后,就可以把IDE作为创建
    测试用例的工具。
    一个Rollup Rule会是这样一种结构

    var manager = new RollupManager();
    manager.addRollupRule({ ... });
    manager.addRollupRule({ ... });
    ...
    具体点就是这样的
    manager.addRollupRule
    (
    {
    name: 'do_search'
    , description: 'performs a search'
    , args:
     [
    name: 'term'
    , description: 'the search term'
          ]
    , commandMatchers:
    [
    {
    command: 'type'
    , target: 'ui=searchPages::search_box\\(.+'
    , updateArgs: function(command, args)
                  {
    var uiSpecifier = new UISpecifier
    (command.target);

    args.term = uiSpecifier.args.term;
    return args;
                  }
    }
    ,
    {
    command: 'click.+'
    , target: 'ui=searchPages::search_go\\(.+'
             }
    ]
    , getExpandedCommands: function(args)
    {
    var commands = [];
    var uiSpecifier = new UISpecifier
         (
    'searchPages'
    , 'search_box'
    , { term: args.term }
    );
            
    commands.push
    (
    {
    command: 'type'
    , target: 'ui=' + uiSpecifier.toString()
              }
    );

    commands.push
    (
    {
    command: 'clickAndWait'
    , target: 'ui=searchPages::search_go()'
               }
    );

    return commands;
    }
    }
    );
    解析:
         在这个例子中,Rollup Rlue被定义成用来执行搜索动作。利用CommandMatcher可
    以将Rule应用到连续的命令集中。Rollup有一个参数:term。之后扩展了原始的两个命令。
    值得注意的是第二个ComandMatcher匹配的是所有以Click开头的命令。这个Rollup可以
    将命令扩展成clickAndWait。下表是Rollup rules对象的所有属性。
     属性名 必选参数否 (数据类型)含义说明
    代码举例
     name  Yes
       
     description  Yes
       
     alternateCommand      
     pre      
     post      
     args  Conditional    
     commandMatchers\
    getRollup()
     Yes    
     expandedCommands\
    getExpandedCommands()
     Yes    








        
  • Selenium UI Element学习笔记(二)

    2009-09-18 11:45:26

    UI Element基础知识篇

         简而言之,这次介绍如何编写基本的Map文件(Extension.js文件)

         一个基本的Map文件大致是这样的:
    var map = new UIMap();

    map.addPageset( {name: 'aPageset',...} );

    map.addElement
    (
    'aPageset'
    , { ... }
    , {}
    );

    map.addElement('aPageset', { ... });
    ...

    map.addPageset( { name: 'anotherPageset', ... } );

         唉,我很晕这样的点啊、大括号、一推单引号的文档描述。没办法,谁让它用的是
    Javascript对象标记方式写的结构呢...先整理一下代码的编写规则:

    1. 映射图的结构被描述成了Map.Pageset.Element的对象链的线性结构。
    2. 一切从一个Map对象开始,即var map = new UIMap()要写在最前面!一个
      Js文件中,最好只写一个Map对象。
    3. 在Map对象后可通过Map对象.addXXX来增加节点(其实就是调用Map对象的Add系列
      方法)。节点的内容用()包围,分号结尾(Javascript的规范写法)
    4. 节点中的内容编写规则如下
    • 字符串要用单引号括起
    • 数组内容用{}括起
    • 数组元素的写法是 数组元素名 : 值。这里的数组元素也可以当做是节点
      对象的属性来看待.需要注意的是这里的元素设置顺序不可改变!
    • 多个数据用逗号分隔,为避免遗漏,建议将逗号写在最前面
    我的编写风格一般是这样的,个人觉得这样看上下关系会比较清楚。
    map.addElement
    (
          {
    'aPageset'
    , name:'testman'
    , description:'man'
    }

    'test'
    );

    搞清楚代码编写规则后,来看看map对象到底提供了什么方法和参数吧

    map.addPageSet(pagesetShorthand
    概述:增加Pageset节点
    pagesetShorthand
    :这是一个数组,其中的元素(Pageset的属性)如下(见文末表1)

    map.addElement(pagesetName, uiElementShorthand)
    概述:在指定的Pageset节点中增加Element子节点
    参数解析
    1.pagesetName 字符串类型,通过设置此参数为Pageset的名字与指定的Pageset进行关联
    2.uiElementShorthand 数组参数,包含了Element的诸多要素(也可看做属性)详细列
    表如下(见文末表2)

    核心方法就这么两个,会不会太单调了呢?当然不只这么点,不过那些以后再说。现在先看
    看与核心方法相关的一些内容吧

    UI Argument Shorthand
         刚才的参数解析中,有提到一个args对吧,这次来仔细看看这个东东里有什么玄机。
    先来看一段实例代码
    map.addElement('searchPages', {
    name: 'result'
    , description: 'link to a result page'
    , args: [
    {
    name: 'index'
    , description: 'the index of the search result'
    , defaultValues: range(1, 21)
    }
    , {
    name: 'type'
    , description: 'the type of result page'
    , defaultValues: [ 'summary', 'detail' ]
    }
    ]
    , getLocator: function(args) {
    var index = args['index'];
    var type = args['type'];
    return "//div[@class='result'][" + index + "]"
    + "/descendant::a[@class='" + type + "']";
    }
    });

    解析:这个Element在定义的时候还指定了args参数,内有两个参数index和type,
    并赋予了默认值(defaultValues语句)。随后在getLocator函数中,将接收这两个参数,
    并在其函数体中起到了动态路径赋值的作用。这里的
    defaultValues语句其实就是用Selenium IDE录制工具录制脚本时自动生成的默认值设置。
    (也就是说,自动生成脚本代码中用到的默认参数设置就是由这个属性决定的)。在IDE的
    录制模式中,IDE使用哪种定位对象方式是自动匹配的,但这往往不准确(这种事情录制时经
    常发生)。UI Element则提供了一种新的UI界面元素定位方式。使用这种方式(即实例代
    码所展示的)时,Selenium通过变换UI Element中定义的所有的参数中默认值来生成一个
    Xpath路径列表,再进行有效匹配。在这段代码中index参数的默认值是1、2、3...20,而
    type参数的默认值是summary和detail。当然,若你不想用IDE,你可以不使用UI
    Argument。
    下表是UI Argument对象的属性介绍(见文末表3)
    关于This关键字

         什么是this:一开始,在使用addPageset() or addElement()函数创建对象时,
    this指的是Selenium IDE的窗口对象(这时的this根本没用)。接着,在geLocator函
    数被调用后,this指的是
    调用此函数的Element对象了。因此,使用this,为UI
    Element定义的任何本地变量就可以使用了。getDefaulVlues函数也是如此。这儿有个有
    点神奇的的地方。若你在UI Element Shorthand部分之前定义你的本地变量,从
    Shorthand语句开始,这些本地变量就可以在arguments中使用通过this引用。注意,这
    不是标准的Javascirpt行为!在理清函数定义语句和避免在函数中使用用于列表和Map的
    全局变量的处理上,这种方式是有效的。这有时会很有用。比如,定义一个映射了人性化
    的参数值到DOM Element ID的参数值的对象。这种情况下,当getLocator函数使用这个
    map对象获得在Locator中的相关ID时,
    getDefaultValues()却可以简单地返回一个
    map对象的属性名。
         特别注意:this关键字仅在getLocator()getDefaultValues()函数中可以
    使用。

    表1

     属性名 是否必选 (数据类型)含义说明
    代码举例
     name  Yes (String)对象的名字,请确保这个名字在一个Map对象中是唯一的。
    name: 'shopPages'
    description  Yes (String)概述这个Pagest方便他人阅读  
    description: 'all pages displaying product'
     pathPrefix  No    
     paths/pathRegexp  Conditional    
     paramRegexps  No    
     pageContent  Conditional    


    表2

     属性名 是否必选
    (数据类型)含义说明
    代码举例
     name  Yes  (String)UI Element的名字
    name: 'article'
    description  Yes  (String)对Element的作用说明,方便阅读此文档  
    description: 'front or issue page link to article'
     args  No  (Array)可修改getLocator函数的参数列表。可以不指定任何参数。  
    [
    { name: 'index'
    , description: 'the index of the author, by article'
    , defaultValues: range(1, 5) }
    ]

    注意,最外层是中括号哦~
    locator/getLocator()  Yes (String\Function)仅可选择两种数据类型之一。若是Function则还可以带参数,此函数的返回值就是这个Element的代码级路径。
     
    locator: 'submit'
    getLocator: function(args) {
    return 'css=div.item:nth-child(' + args.index + ')'
    + ' > h5 > a';
    }
    getLocator: function(args) {
    var label = args.label;
    var id = this._idMap[label];
    return '//input[@id=' + id.quoteForXPath() + ']';
    }
     genericLocator/getGenericLocator  No    
     getOffsetLocator  No    
     testcase*  No    
     _*  No  (Any Data Type)为UI Element声明本地变量。这种变量在UI Element的getLocator函数和任何通过它进行参数传递的任何getDefaultValues函数中有效。这些变量以"_"开头。写法见代码举例。
     
    _labelMap: {
    'Name': 'user'
    , 'Email': 'em'
    , 'Phone': 'tel'
    }

    表3

     属性名 是否必选
    (数据类型)含义说明
    代码举例
     name  Yes  (String)参数的名字  
    name: 'index'
    description  Yes  (String)参数的易读性描述  
    description: 'the index of the article'
    defaultValues/getDefaultValues()  Yes
     (Array\Funcition)仅可选择两种数据类型之一。getDefaultValues(inDocument),这是此函数的结构。inDocument参数是录制时的当前页面的Document对象。
    defaultValues: [ 'alpha', 'beta', 'unlimited' ]
    getDefaultValues: function() {
    return keys(this._idMap);
    }
    getDefaultValues: function(inDocument) {
    var defaultValues = [];
    var links = inDocument
    .getElementsByTagName('a');
    for (var i = 0; i < links.length; ++i) {
    var link = links[i];
    if (link.className == 'category') {
    defaultValues.push(link.innerHTML);
    }
    }
    return defaultValues;
    }

  • Selenium UI Element学习笔记(一)

    2009-09-18 10:05:45

    简介
         Selenium UI Element是Selenium的特性之一。它使对网页的上的各种页面元素的用户含义与开发含义之间进行一种映射的想法成为可能。这样的映射是通过JavaSript对象标记法实现的,而且它可以在Selenium IDE和RC两种开发模式下共用。它也为日后脚本维护(页面对象变化了)提供了统一的维护方式。

    一、名词术语
    Page
         页面。一般来讲就是能够以指定的URL访问的具体网页的页面。专业点说就是一个Page是一个包括URL地址信息的DOM文档对象。

    Page Element
         一个网页上的各种构成要素。一般来讲,所有可与用户进行交互和所有有意义的内容都是Page Element。专业点说,一个Page Element就是一个DOM文档对象的一个节点和该节点的内容。因此,当我们在看待一个Page Element时应同时认识到以下两点:1.它是页面上的某样东西 2.它是DOM的具体表现形式,包括一个元素和其他元素之间的关系。

    Pageset
         共有页面设置。简单来说就是对一些通用页面元素的统一设置。你可以设计多个不同的Pageset,这没有限制。同样的,一个UI Element也可以包含在多个不同的Pageset中。Pageset一般会使用正则表达式来描述某一指定的网页页面。当然,要正确识别一个Page Element还有很多种情况需要考虑。对了,每个Pageset要给它取一个独一无二的名字哦~

    UI Element
         在Page Element的实际意义与定位DOM文档对象的节点路径之间所作的映射。Page Element通过定位器(Locator)进行查找,UI Element属于Pageset中内容。

    UI Argument
         界面参数。根据UI Element决定怎样生成定位器的的一个逻辑细节。Pageset中,它是不是必须的内容。但它经常被用在同一页面上出现多个相似Page Element的情况下区别相似Element,而且你也想通过单一的Element来统一识别它们。举例来说,若一个页面上展现了20条可双击打开的搜索结果记录,这个搜索结果的索引就是一个UI Element。

    UI Map
         界面映射图。一个包含所有Pagset的集合体,当然也包括了所有的UI Element。它是一个负责在UI specifier strings、Page Element和UI Element之间进行交流的中间件。

    UI specifier strings
         界面定义字符串信息。它包括Pageset的名称、UI Element的名称、可选参数的名称。这些文本是为了方便人们阅读文档而建立的。

    Rollup rule
         描述了怎样将多个Selenium命令组合成一条单一的命令以及如何将这样的单一命令做成Selenium组件的方法。这些单一的命令被称作“rollup”

    Command Matcher
         命令匹配器。一般做成一个Rollup Rlue后,用Command Matcher可以一个或多个Selenium Commands并有选择地对匹配的命令设置rollup参数值。一个Rollup rule一般会有多个命令匹配器。


        先来看看定义好UI Element后,在Selenium中网页对象的名字是什么样的吧:
    ui=allPages::section(section=topics)
    ui=subtopicListingPages::subtopic(subtopic=Creativity)

    记住这样的表示方式,以后还会有更深入的介绍。




  • Selenium学习报告

    2009-09-03 00:05:22

        花了几天时间,把Selenium的东西都大概浏览了一番。整体感受是当今的软件研发越来越推崇拆分设计、组合安装的设计思想了。过去用的是Test Complete,当时因为它不像QTP那样高度集成而不满过一阵子。后来,理解了它的结构后,才发现它拆那么散是为了具有灵活应变的特性所必须做出的牺牲。现在Selenium...同样的情况,不同的心情。Test Complete中再怎么拆,它都在Test Complete这个大环境之中。这次,我应该总结成我在学习Web 测试新技术会更恰当一些。因为要想在Web 测试上实现高度复用、灵活应变需求的自动化测试,它需要的是多个软件、技术的一整套整合才可以实现。简单来说,拿Test Complete的特性与Web测试中的内容作个比较就可略知一二了:

        Test Complete  & Web Testing特性对照表

        特性 Test Complete实现方法

              Web Testing实现方法 

     别名映射 Namemapping  Selenium IDE UI Element
     网页对象对象识别模式 Tag  Xpath
     数据驱动 DDT  Test NG\Selenium Core HTML
     跨浏览器与可编程基础 无  Selenium RC
     面向对象编程 Java Script  Java Coding 
     Ext对象操作 无  Java Script
     网页对象操作脚本 TC Record   Selenium IDE
     自定义测试报告 Log系列方法  XML 
     负载测试 内置功能  Selenium Grid 

        可以想象,以后要做自动化测试很有可能是这样一种情形:
        1.设计测试用例
        2.在Test NG单元测试框架下编写测试集
        3.将通过Selenium IDE将网页操作记录成的脚本放到测试集的方法中(熟练后就可直接写代码了)
        4.启动Selenium RC
        5.在Test NG中执行测试,生成的测试报告则从Test NG中生成好了(连统计功能都提供了,省很多事啊)
        6.在实践中总结问题,逐步优化异常处理机制

        报告先记录到此,后面有一堆东西要学,以后再总结~

Open Toolbar