记录阿里巴巴QA架构组成长点滴。2008年关键词为效率,技术,影响力!QA/测试架构师定义:开发和设计测试框架测试库;纵横全局的考虑产品的功能,设计复杂的测试系统;负责研发某一项特定的测试技术;为公司考虑如何提高测试效率。领导公司测试技术的发展和测试策略上的方向,关注整个公司的测试部门的问题,前瞻性的考虑未来的版本的测试策略和技术。测试架构师计划/设计测试平台,关注着产品的测试过程,提供咨询服务,影响到公司内的测试机构测试社区,以及开发机构等,对产品各个方面施加深远而正确的影响,最终提高整体软件质量。

发布新日志

  • php 执行linux 命令

    2008-12-10 19:23:54

    by leshui

    dargoon项目,自动化跑测试用例

    ini_set("display_errors", "On");
    error_reporting(E_ALL);
    include_once("lib.test.php");
    $lib=new libtest();
    $lib->db_conn();
    //测试时间段角本;
    $array_case=file("testcase/time_case.txt");
    //$array_case[0]="'sssss'";
    $sql="select * from device_service where dev_service_id=6";
    $array_db=$lib->getall($sql);
    $sc_name=$array_db[0]["scrīpt_name"];
    echo $sc_name."------------------------------------";
    $logname="log_".time().".log";$al_lgos="";
    foreach ($array_case as $k=>$case){
     $al_lgos="";
     //修改数据库
     $upsql="update device_service set run_time_range=\"".trim($case)."\" where dev_service_id=6 limit 1";
     $lib->db_excute($upsql); 
     sleep(1);
     //执行 agent ====================================
     exec("/home/qjy/src/agent/aliprobe -d /home/qjy/src/agent/cps/ -a 0.0.0.0:7777 -m 10.2.6.21:6000 -i 1 -v3 --debug  > sagent.txt &");
     sleep(10);
     //kill agent ===================================
     exec("netstat -nlp > test.txt ");
     sleep(2);
     $array_agent=file("test.txt"); 
     //根据端口号 0.0.0.0:7777  kill 线程
     foreach ($array_agent as $k1=>$v1){
      if (ereg("0.0.0.0:7777",$v1)){
       if (ereg ("([0-9]{1,10})/python", $v1, $regs)){
        $pid=$regs[1];
        exec("kill -9 ".$pid);
        sleep(1);
       }  
      }
     }
     sleep(2);
     //分析日志 =======================================
     //是否存在 $sc_name
     $al_lgos.=$case." ==============================      \r\n";
     $array_agent_logs=file("sagent.txt");
     $err=0; $ok=0; $check=0; $error_lgos="";
     foreach ($array_agent_logs as $keys=>$agent_logs){
      if (ereg($sc_name,$agent_logs)){
       //$al_lgos.="已检测试到".$sc_name." ||||| ".$agent_logs." \r\n";
       if (eregi("Loading check: ".$sc_name,$agent_logs)){
        //存在 说明发送成功
        //eregi("(Loading check: ".$sc_name.").*?",$agent_logs,$args);   
        $al_lgos.="发送成功 "." ||||| ".$agent_logs."\r\n";
        $ok=1;   
       }
       $check=1;
      }
      
      if (eregi("ERROR",$agent_logs)){
       $error_lgos.="**********错误 **************:"." ||||| ".$agent_logs." \r\n";
      }
      
     } 
     
     if ($check==0){
      $al_lgos.="====未检测试到====".$sc_name." \r\n";
     }
     if ($ok==0){
      $al_lgos.="----------角本".$sc_name." 没有发送成功--------- \r\n";
     }
     $al_lgos.=$error_lgos;
     $al_lgos.=" end ======================================== \r\n"; 
     $al_lgos.="\r\n";
     
     //输出分析日志 =======================================  
     $handle = fopen("analysis/".$logname, 'a');
     fwrite($handle, $al_lgos);
     fclose($handle);
     //break;
    }

  • ruby正则表达式快速指南

    2008-12-09 09:28:43

    by jiale

    [abc]        A single character: a, b or c
    [^abc]      Any single character but a, b, or c
    [a-z]        Any single character in the range a-z
    [a-zA-Z]   Any single character in the range a-z or A-Z
    ^             Start of string
    $             End of string
    (...)         Capture everything enclosed

    .             Any single character
    \s           Any whitespace character
    \S           Any non-whitespace character
    \d           Any digit
    \D           Any non-digit
    \w           Any word character (letter, number, or underscore)
    \W          Any non-word character

    (a|b)       a or b
    a?           Zero or one of a
    a*           Zero or more of a
    a+           One or more of a
    a{3}       Exactly 3 of a
    a{3,}      3 or more of a
    a{3,6}    Between 3 and 6 of a

  • kill process(ruby)

    2008-11-24 09:35:52

    def kill_process(name)
            begin
              wmi = WIN32OLE.connect("winmgmts://")
              processes = wmi.ExecQuery("select * from win32_process where name='#{name}'")
              for process in processes
                process.terminate()
                sleep 0.2
              end
            rescue => err
              $LOG.fatal(err)
              raise err
            end
          end
  • bat获取ruby安装路径

    2008-11-24 09:19:50

    picassoWR的install程序希望在ruby安装完成后,获取ruby的安装路径并写入到path环境变量中,bat可以通过REG QUERY方法获取ruby的安装路径

    for /f "skip=4 tokens=1,2 delims=:" %%a in ('reg query HKLM\SOFTWARE\RubyInstaller /v Path') do (

      set RubyPathL=%%a

      set RubyPathR=%%b

    )
    set RubyPath=%RubyPathL:~-1%:%RubyPathR%

    将RubyPath写入Path环境变量,bat需要通过更新注册表的方式更新path环境变量

    REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v path /t REG_SZ /d "%PATH%" /f

  • 批处理抓取页面中图片对象

    2008-11-23 20:37:59

    By Wiston Li

    watir底层中很多集合类代码如:buttons, divs, links, spans等等,方便用户用each方法来枚举。

    例如下面代码,把所有image生成保存到本地。

    require 'watir'
    browser = Watir::IE.new
    browser.goto('http://twitter.com')
    
    idx = 0
    browser.images.each do |x|
      idx += 1
      location = 'c:\tmp\file-' + idx.to_s + '.jpg'
      x.save(location)
    end
    
  • 扩展watir底层,调用visible返回对象是否可见

    2008-11-23 20:31:08

    By Wiston Li

    在用developer toolbar inspect一个对象时,属性display= none or visibility= hidden 或其父对象是hidden时,此对象在页面上显示是invisible的。

    下面的方法扩展element类,并修复1.5.6bug,在写watir脚本时,即可调用object.visible?方法.

     

    class Watir::Element

     
      def visible?
     
        ōbject = document
        while object
          begin
            if object.currentstyle.invoke('visibility') =~ /^hidden$/i

              return false
            end
            if object.currentstyle.invoke('display') =~ /^none$/i

              return false
            end
            if object.invoke('isDisabled')
              return false
            end
          rescue WIN32OLERuntimeError
          end
          ōbject = object.parentElement
        end
        true
      end
    end

    watir脚本:

    require 'watir'
    include Watir

    ie = IE.new
    ie.goto("www.someplace.com")
    button = ie.button(:id, 'somebutton')
    if button.visible? '调用visible方法
      button.click
    else
      ie.close
    end

     

  • 获取选择框页面对象的value值

    2008-11-23 19:50:14

    By Wiston Li

    在对页面中选择框对象进行操作时,页面显示的对象对应其item属性,如:checkbox, radiobox,select list等,但程序逻辑判断处理时,实现上是取item对应的value值,那么watir自动化脚本时,如何取到相应的value?

    页面代码:

     <input type="radio" name="email_frequency" value="daily">Daily Email</
    input>
     <input type="radio" name="email_frequency" value="weekly">Weekly
    Email</input>
     <input type="radio" name="email_frequency" value="monthly">Monthly
    Email</input>

    watir脚本:

      def get_values_by_name(name)
        value_list = []
        @browser.document.getElementsByName(name).each do |el|
          value_list << el.attributes('value').value
        end
        return value_list
      end

    用上述方法即可访问到value。但其调用getElementsByName,会访问到所有对象,后续,将研究一下@o.invoke来试试,直接封装到底层,只是针对某个web对象来操作.扩展watir功能。

  • watir自动化测试结果报告输出

    2008-11-23 18:47:22

    By Wiston Li

    我们知道,ruby安装好后,其gem包已经安装log4r,在开发watir自动化脚本时可以引用,非常方便

    代码问题定位,log定制,异常栈输出。但是针对用例执行时对于检查点与步骤信息,可以用HTML加简单CSS

    友好显示输出结果,不过,要想做到很强大,最终还是要写到数据库中,方便查询和统计。

    引用代码:

    # Load classes
    require 'rubygems'
    require 'watir'

    # The main test
    begin
      # Create the new report
      r = CLReport.new()
      testReport = r.createReport('C:\\testlocation\\reports\\Examplescrīpt')

      # Start browser
      browser = Watir::IE.new
      browser.goto('http://www.blabla.com')

      # --- START TEST ---

      # Do a check and report the result
      if (1 > 0)
        r.addtoReport(testReport, 'Check if 1 is bigger than 0', 'PASSED', '1 is indeed bigger than 0')
      else
        r.addtoReport(testReport, 'Check if 1 is bigger than 0', 'FAILED', '1 is NOT bigger than 0!')
      end

      # Do another check and report the result
      if (2 > 1)
        r.addtoReport(testReport, 'Check if 2 is bigger than 1', 'PASSED', '2 is indeed bigger than 1')
      else
        r.addtoReport(testReport, 'Check if 2 is bigger than 1', 'FAILED', '2 is NOT bigger than 1!')
      end

      # --- END TEST ---

      # Close browser
      browser.close

      # Finish the report
      r.finishReport(testReport)
    rescue
      # Send crash info to report
      r.addtoReport(testReport, 'Test crashed with reason '+$!, 'FAILED', 'Test crashed!')

      # Finish the report
      r.finishReport(testReport)
    end

    CLReport类代码,请参见附件中(点文件菜单访问)。

     

  • [watir] 在watir中读取ini文件

    2008-11-23 16:29:10

                                                                   --------by nish

      在window系统中,ini文件是一个很重要的配置文件,很多软件都通过ini文件的方式来进行参数的配置。在参考了网上gdsx in #ruby-lang中的一部分代码,写了读取ini文件的函数,该函数支持正则等,同时改进了原先代码中不支持等于号后有"="的情况。代码如下:

    def read_ini_file(filename)
        input = ""
        File.open(filename){|f| input = f.read}
        tamed = {}
        
        # split data on city names, throwing out surrounding brackets
        input = input.split(/\[([^\]]+)\]/)[1..-1]
     
        # sort the data into key/value pairs
        input.inject([]) {|tary, field|
          tary << field
          if(tary.length == 2)
            # we have a key and value; put 'em to use
            tamed[tary[0]] = tary[1].sub(/^\s+/,'').sub(/\s+$/,'')
            # pass along a fresh temp-array
            tary.clear
          end
          tary
        }
     
        tamed.dup.each { |tkey, tval|
          tvlist = tval.split(/[\r\n]+/)
          tamed[tkey] = tvlist.inject({}) { |hash, val|
            array = val.split(/=/)
            k = array[0]
            v = array[1..-1].join("=")
            k = k.strip        
            v= v.strip unless v.nil?  
            v =" " if  v.nil?
            first = v[0,1]
            last = v[-1,1]
            flag = first + last
            case flag
            when "\"\""
              v = v[1..-2]
            when "//"
              v = /#{v[1..-2]}/
            end
            hash[k]=v
            hash
          }
        }
      
        tamed
      end


     

    假设ini文件如下:

    [test]

    key1 = /test/

    key2 = "xxxxx"

    [test2]

    key1 = xxxx

    key2 = yyyyy

     则通过上述函数,读取后的内容为(返回的结果为一个Hash)

    result={

     "test"={

            "key1" = /test/,

            "key2" = "xxxxx"

            },

    "test2"={

         "key1" ="xxxx",

         "key2" = "yyyyy"

     }

    }

  • [watir] watir中close方法的改进

    2008-11-23 16:22:18

                                     ------by nish

      在watir中,默认的close的方法是通过调用ole的quit方法来实现的。但是由于quit方法需要执行一定时间。在多次运行的过程中,经常会出现ole错误,远程连接已经断开的错误。出现这个错误的原因是因为close方法中的quit方法还没有将ole对象完全destroy从而导致。

      找到原因后,改进的方法也就很简单,就是在close方法中加入判断,知道要关闭的IE对象的ole对象完全destroy后才退出close方法。可以通过以下的代码实现:

     

        def close
          @closing = true
          @ie.quit
          begin
            while
              @ie.HWND
            end
          rescue WIN32OLERuntimeError
          end
        end   

      该方法通过在调用quit方法后,再去不断的调用hwnd方法,知道ole对象销毁报错后退出程序的执行。

  • [rails学习] 在rails中使用thickbox.js

    2008-10-22 17:36:46

                                                                     ----by Nish

      thickbox.js是一个基于jquery的很不错的插件,但是由于rails默认的使用的是Prototype这个Ajax库,所以在rails中简单的通过以下代码,会出现jquery与Prototype的冲突。

      <%= javascrīpt_include_tag  'jquery' %> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

     目前有2种方法可以解决上面的方法:

    第一种是在引入上述js库中,增加一行代码 <scrīpt> jQuery.noConflict(); </scrīpt> ,即上述代码改为:

      <%= javascrīpt_include_tag  'jquery' %> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

      <scrīpt> jQuery.noConflict(); </scrīpt>


    第二种方式是使用jrails代替默认的 Prototype库。

    jrais可以通过下面命令进行安装

    ruby ./scrīpt/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails

    安装完成后,会自动把jrails用的js文件拷贝到Javascrīpt文件夹下,然后删除所有Prototype库所带的的js文件,通过下面的代码就可以正常的使用thickbox,并且,默认的,rails用的ajax库改成了jquery

      <%= javascrīpt_include_tag  :default%> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

    或者

      <%= javascrīpt_include_tag  'jquery','jquery-ui','jrails'%> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

  • ruby设置windows环境变量

    2008-10-08 11:25:23

    by jiale

    ruby可以使用win32ole.new("Wscrīpt.Shell")的Environment操作windows环境变量

    获取环境变量:

    win32ole.new("Wscrīpt.Shell").Environment(type).Item(name)

    type:system(系统)、user(用户)

    name:环境变量名

    设置环境变量:

    vbs的做法:

    可以直接使用

    win32ole.new("Wscrīpt.Shell").Environment(type).item(name) = value

    但在ruby中item(name) = value会抛语法异常

    ruby的做法:

    win32ole.new("Wscrīpt.Shell").Environment(type)["item",name] = value

    或者使用setproperty方法

    win32ole.new("Wscrīpt.Shell").Environment(type).setproperty("item", name, value)

  • ruby获取目标页面源文件

    2008-10-08 09:58:03

    by jiale

    #获取http源文件

    require 'net/http'
    def get_httpsource(searchurl)
       begin
          url = URI.parse(searchurl)
          res = Net::HTTP.get(url)
          return res
       rescue => err
          puts err
          raise err
       end
    end

  • Ruby获取当前的执行文件的路径和目录

    2008-10-08 09:53:21

    by jiale

    获得当前执行文件的文件名:

    __FILE__

    获得当前文件的目录

    File.dirname(__FILE__)

    获得当前执行文件的完整路径(绝对路径)

    require ‘pathname’
    Pathname.new(__FILE__).realpath

    获得当前执行文件的目录完整路径(绝对路径)

    require ‘pathname’
    Pathname.new(File.dirname(__FILE__)).realpath

  • 批量点击链接(去重)

    2008-09-24 19:26:45

    by jack

    日前忽然有人问我,想把一个页面上的搜索结果链接都点一遍分别检查,这个脚本怎么写

    想想这个需求很简单,就顺手用descrīption对象写了,以口碑网搜索结果为例,脚本如下:

    SystemUtil.Run "http://bendi.koubei.com/search/searchlocal.html?option.key=%D1%C5%CA%CB%D4%B7&option.cityname=%BA%BC%D6%DD&searchFlag=1&city=2595"


    Set ōDesc = Descrīption.Create()

    oDesc("micclass").Value="Link"
    oDesc("url").Value="http://hangzhou.koubei.com/store/detail--storeId-.*"

    Set Lists = Browser("title:=雅虎口碑.*").Page("title:=雅虎口碑.*").ChildObjects(oDesc)
    NumberOfLists = Lists.Count()

    For i = 0 To NumberOfLists - 1 
      Lists(i).click
      ……
    Next

    点击的都是http://hangzhou.koubei.com/store/detail--storeId-这种格式的链接,也就是结果链接的统一格式

    这里有个点要注意:descrīption对象默认就是支持正则表达式的,可以用正则表达式作为属性值

    但是很快就反馈回来一个问题:页面上有重复的链接,这样实际是存在重复点击的;在结果比对时出现了点问题

    想了想,就再加入了一段去重的处理,修改脚本如下:

     

    SystemUtil.Run "http://bendi.koubei.com/search/searchlocal.html?option.key=%D1%C5%CA%CB%D4%B7&option.cityname=%BA%BC%D6%DD&searchFlag=1&city=2595"


    Dim arrClickedLink()
    ReDim Preserve arrClickedLink(0)

    Set ōDesc = Descrīption.Create()

    oDesc("micclass").Value="Link"
    oDesc("url").Value="http://hangzhou.koubei.com/store/detail--storeId-.*"

    Set Lists = Browser("title:=雅虎口碑.*").Page("title:=雅虎口碑.*").ChildObjects(oDesc)
    NumberOfLists = Lists.Count()

    For i = 0 To NumberOfLists - 1
        sCurrentLink = Lists(i).getroproperty("url")
     If not isClickedLink(sCurrentLink) Then
      Lists(i).click
      ……
     End If
    Next

    Function isClickedLink(url)

     iClickedLinkLen = ubound(arrClickedLink)

     For n=0 to iClickedLinkLen
      If url = arrClickedLink(n) Then
       isClickedLink = True
       Exit Function
      End If
     Next

     ReDim Preserve arrClickedLink(iClickedLinkLen+1)
     arrClickedLink(iClickedLinkLen+1) = url
     isClickedLink = False

    End Function

     

     

  • 利用托盘程序显示自动化执行进度

    2008-09-17 11:12:36

    by jiale

    在自动化执行过程中需要显示自动化执行的进度,如果使用msgbox,就需要人工干预,且无法一直显示执行进度并实时刷新,理想的结果是脱离qtp且能够实时得到执行的进度。

    在自动化执行过程中将执行进度写入文本文件,利用windos托盘程序,实时读某文件,且利用托盘程序并可显示或隐藏进度窗口。

    vb托盘程序在网上可以轻易找到,不再附上。

  • webtable对象,利用嵌套字典对象来转化,从而具有逻辑意义

    2008-09-10 20:25:07


    by Wiston Li

    页面中存有大量的webtable,利用getcelldata方法,需要指定行、列的index. 但若在页面上用户

    进行操作上排序,数据排列将发生变化,下面的方法,利用嵌套字典对象来转化,从而具有逻辑意义

    表现访问单元格的值,从而减少参考物理单元格。(数据表如附件所示:)

     

     

     Dim oDataTable
     Dim solarExch
     Dim nRows

     set  ōDataTable=objIdentifyPage ("阿里助手","n").WebTable("text:=操作指南.*","index:=0").WebTable("text:=选择.*")
     Set solarExch = CreateObject("scrīpting.Dictionary")
     nRows=oDataTable.rowcount  
     For  nRow=2 to nRows
      symbolKey =oDataTable.getcelldata(nRow,2)
      solarExch.add symbolkey, createObject("scrīpting.Dictionary")
      solarExch(symbolKey).add "quantity", oDataTable.getcelldata(nRow,3)
      solarExch(symbolKey).add "price", oDataTable.getcelldata(nRow,4)
      solarExch(symbolKey).add "oneprice", oDataTable.getcelldata(nRow,5)
      solarExch(symbolKey).add "highprice", oDataTable.getcelldata(nRow,6)
      solarExch(symbolKey).add "situation", oDataTable.getcelldata(nRow,7)
      
     Next

        msgbox solarExch("asf").item("oneprice")'显示附土中,asf(关键词)这一行,一口价的值,并不依赖当前行列的顺序,即便重新排序。
        msgbox solarExch("试纸").item("price")

  • QTP api中大小写敏感的bug

    2008-09-10 19:38:20

    by wiston li

    qtp中提供对webtable对象操作一系列的api方法,今天在对childitem使用时,令我非常晕的是,曾经使用过多次这个方法,今天突然不奏效了,原因就是很简单,传递的web object的class name大小写是敏感的,

    在help里查了半天,也没有具体定义说明,故我称其bug.

     

    dim oDataTable, iRows

    Set ōDataTable = objIdentifyPage (sTitle,"n").

    WebTable("text:=选 词.*", "index:=0").WebTable("text:=选择.*", "index:=0")
    iRows= oDataTable.RowCount

     If iRows >=2  then
      Call reportManager("Pass", "webtable中数据记录检查", "当前数据表中有数据","有记录存在!","")

      Set ōWebLink =objIdentifyPage (sTitle,"n").WebTable("text:=选 词.*", "index:=0").WebTable("text:=选择.*", "index:=0").childItem(winGetRandNum(2, iRows), 2, "Link", 0 ) ' 如果使用childItem(winGetRandNum(2, iRows), 2, "link", 0 ),QTP即会报错。
      oWebLink.click
      objCloseIE sTitle,"1"   

    else
      Call reportManager("Warning", "webtable中数据记录检查", "当前数据表中有数据","没有记录存在, 数据已被误操作删除,请为此关键词准备竞价数据!","")
      
     end if

  • 如何修改QTP脚本默认打开/保存的目录?

    2008-08-20 19:44:04

    By Wiston Li

    QTP脚本开发,每次都要打开文件夹,却总是默认从C:\Program Files\Mercury Interactive\QuickTest Professional\Tests来找文件,

    但基于框架开发的脚本,是保存在src\case里的,今天捣腾了一下,其默认的目录是可以修改的,

    修改注册表:

    1, HKEY_current_user\software\MI\QTP\mictest\TestsDirectory

    2, HKEY_local_machine\software\MI\QTP\mictest\TestsDirectory

    修改为:

    D:\svn\10_QAArchitech_scrīpts\src

    重启QTP,看一下,再打开文件是不是已经修改自定义的目录?是不是操作使用起来很爽。。。

    节约个几秒是几秒,不要把心情弄槽。。。

     

     

  • 异常对象识别(Watir应用解决方案)

    2008-08-11 19:29:18

    5. 异常对象识别(Watir应用解决方案)

    Watir基于处理,继承于web document的对象提供较好的支持方法,但相对于处理windows对象较弱. 就目前从各网站收集的对象来看, 基本上,对于在IE实例对象打开的web标准对象
    能够成功识别与操作,其它的脱离当前IE窗口,打开的所有弹出框都不能正常识别。其中,弹出框对象占有异常对象识别中很大一部分。
    目前碰到的弹出框, 我把他们分为三大类型:
    1, Alerts 警告作用,如:sorry, 当前用户没有权限操作
    2, Confirm 需要操作按钮, 如:你确认要删除当前记录?
    3, Prompt+ select +confirm  需要用户输入,操作查询或点击, 最后确认, 如:Download/upload (浏览+选择文件)

    下面给出,上面几种弹出框watir实现识别与操作的方法,
    5.1. 弹出框基于autoIT + 线程实现方式

    此种方法,对于第一、二种弹出框操作较有效,
    因点击某个link/button等对象,而弹出的窗口(大部分弹出框可应用此种方式来实现。)

    1, 定义方法

    def check_for_popups
        autoit = WIN32OLE.new('AutoItX3.Control')
        #
       
        # Do forever - assumes popups could occur anywhere/anytime in your application.
        loop do
            # Look for window with given title. Give up after 1 second.
           
            ret = autoit.WinWait('消息 -- 网页对话框', '', 1)
            #ret = WinActivate("Microsoft Internet Explorer", "")
    #autoit.ControlClick("Microsoft Internet Explorer", "", "[CLASS:Button; INSTANCE:1]", 2)
           
            puts(ret)
            #
            # If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
           
            if (ret==1) then autoit.Send("{Enter}") end
           
            #
            # Take a rest to avoid chewing up cycles and give another thread a go.
            # Then resume the loop.
            sleep(3)
        end
      end


    2, 程序体代码

    ie.button(:name, "signin").click_no_wait

    sleep(20)

    $popup = Thread.new { check_for_popups }  # start popup handler

    at_exit { Thread.kill($popup) }

     


    5.2. Call 另一ruby文件

    对于第二种弹出框,像安全警告点击, 并不通过操作与点击任何对象, 即呈现弹出窗口。
    我尝试用3.1方法来实现,不成功。用下面方法替代:


    1, 在watir/WindowHelper.rb文件中增加方法

       def push_security_alert_yes_cn
            @autoit.WinWait "安全警报", ""
            @autoit.Send "{TAB}"
            @autoit.Send "{TAB}"
            @autoit.Send "{SPACE}"
          End

    2, 定义另一调用文件 tmp.rb
    require 'watir/WindowHelper'
    helper = WindowHelper.new
    helper.push_security_alert_cn_yes


    3, 在打开安全URL之前,启动调用ruby文件

    require 'rubygems'
    require 'watir'   # the watir controller
    require 'win32ole'
    require 'watir/WindowHelper'


    Thread.new{system('ruby c:\tmp.rb')} #你定义tmp文件存放路径
    ie = Watir::IE.new
    ie.goto("http://www.alipay.com.cn/")
    5.3. 修改框架底层

    此种方法,针对弹出框3.

    举例一, 上传下载文件
    1, 修改底层代码input_elements.rb文件,
    类 FileField中, 方法set.
    为了支持中文,有一句替换修改为:

    system("rubyw -e \"require 'win32ole'; @autoit=WIN32OLE.new('AutoItX3.Control'); waitresult=@autoit.WinWait '选择文件', '', 15; sleep 1; if waitresult == 1\" -e \"@autoit.ControlSetText '选择文件', '', 'Edit1', '#{setPath}'; @autoit.ControlSend '选择文件', '', 'Button2', '{ENTER}';\" -e \"end\"")


    2, 定义方法
    def save_file(filepath)
        ai = WIN32OLE.new("AutoItX3.Control")
        ai.WinWait("文件下载", "", 5)
        ai.ControlFocus("文件下载", "", "保存(&S)")
        sleep 1
        ai.ControlClick("文件下载", "", "保存(&S)", "left")
        ai.WinWait("另存为", "", 5)
        sleep 1
        ai.ControlSend("另存为", "", "Edit1",filepath)
        ai.ControlClick("另存为", "", "保存(&S)", "left")
        ai.WinWait("下载完毕", "", 5)
        ai.ControlClick("下载完毕", "", "关闭")
      end


    3, 程序体代码:
    ie.file_field(:name, "xlsfile").set("c:\\samenameobject.html")
    #上传你所指定的文件


    ie.span(:text, "导出Excel表").click_no_wait
    save_file("C:\\abc.xls")
    #下载到你所指定的路径

     

    针对弹出框3, 需要用户介入查询并操作:
    举例二, 中供crm中类目与客户选择的弹出框,与第一种实现方式不同在于,
    用到autoit中WinActivate与ControlClick方法,


    require 'rubygems'
    require 'watir'   # the watir controller
     require 'watir/WindowHelper'
     
    require 'win32ole'


    def check_for_popups
     
    autoit = WIN32OLE.new('AutoItX3.Control')

    loop do
          ret = autoit.Winwait("选择 -- 网页对话框", "", 1)
          puts ret
         if (ret==1) then
           autoit.WinActivate("[CLASS:Internet Explorer_TridentDlgFrame]", "")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")

          #autoit.Send("湖州")
          #autoit.Send("{ASC 2709}")
          #autoit.SendUnicode("a")
          #autoit.ClipPut ("杭")
          #autoit.ClipGet
          #autoit.ToolTip "This is a tooltip杭州", 0, 0
          #autoit.Sleep 2000  
         
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{Enter}")

          autoit.WinActivate("[CLASS:Internet Explorer_TridentDlgFrame]", "")
          autoit.ControlClick("选择 -- 网页对话框", "", "[CLASS:Internet Explorer_TridentLstBox; INSTANCE:2]", 2)

          autoit.Send("{TAB}")
          autoit.Send("{Enter}")

          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{Enter}")
        end
        sleep(3)
      end

    end


    ie=Watir::IE.new
    ie.goto("http://10.2.6.4:5100/bin/member/signin")
    #ie.goto("http://10.2.6.4:5100/")


    #ie.element_by_xpath("//span[contains(text(), 'Main Road Nijmegen')]").click

    ie.text_field(:name, "id").set("mhl1805") 
    ie.text_field(:name, "password").set("zxcvbnm")

    ie.button(:name, "signin").click


    ie.frame(:name, "left").link(:url, "http://10.2.6.4:5100/v3/help_cust.htm").click

    ie.frame(:name, "left").link(:text, "新签中供客户").click

     # start popup handler


    ie.frame(:name, "right").frame(:name, "rtop").button(:value, "选择客户").click_no_wait
    sleep(20)

    $popup = Thread.new { check_for_popups }

    at_exit { Thread.kill($popup) }

    针对第三种popup window, 如果需要与用户交互,且需要输入中文时,若用autoit sendkey对待中文支持(但官方文档说支持中文输入, 网上有不少人和我遇到同样问题),尚没有找到有效方案,有待进一步跟进。

       除上述弹出框需要特殊处理外,watir中也有一些扩展tag,或第三方控件需要特殊处理的,
       像:
    5.4. web HTML编辑器
    中文站的html编辑器提供: 操作ID或name操作起来较方便直接

    require 'rubygems'
    require 'watir'   # the watir controller
    require 'watir/WindowHelper'
    require 'win32ole'
    ie=Watir::IE.new

    ie=Watir::IE.attach(:title, /阿里助手/)
     
    ie.text_field(:name, "_fmo.a._0.s").set("mhl1805") 
    ie.document.getElementByid("_editor").contentWindow.focus()
    ie.send_keys("abcsadfasfd")


    但也碰到有些web页面,不提供任何ID,只能用autoIT方法来send tab实现


    require 'rubygems'
    require 'watir'   # the watir controller
    require 'watir/WindowHelper'
    require 'win32ole'


         


    ie=Watir::IE.new

    #ie=Watir::IE.attach(:title, /Alibaba/)

    ie.goto('http://us.my.alibaba.com/product/buyoffer/post_buying_lead.htm')

    ie.text_field(:name, "_fmp.bu._0.su").set("mhl1805") 
    ie.text_field(:name, "_fmp.bu._0.su").set("中国人") 


    ie.checkbox(:id, "detailDesc").set
    ie.checkbox(:id, "detailDesc").focus()
    ie.send_keys("\t"*9)
    ie.send_keys('Hello Worldabcdef')


    5.5. 对象识别其它常用TAG内置方法引用

    如:IE.div , ie.span, ie.cell, ie.table方法,可以实现点击操作,取值操作等.
    另外提供QTP类似描述性编程,同类型对象统计:

    ie.buttons.each { |b| puts b.to_s }
     puts ie.checkboxes.length  
     puts ie.links.length 
     puts ie.buttons.length等等 

    对于常用的innertext属性, 在watir中已经封装到方法,可以直接引用。如:
    ruby在对象识别底层,封装了innertext
    实现,调用方法text即可:
    如:puts ie.div(:id, "intelligentWord").link(:id, index.to_s).text

    最后:返回文本与源代码,用下面方法:
    puts ie.text()
    puts ie.html() 

    5.6. 识别对象正则表达式支持
     
    当然,ruby提供强大的正则表达式支持,如:属性标识正则
    ie=Watir::IE.attach(:title, /Alibaba/)

    Ruby的正则表达式以"//"作为基本框架,表达式内容位于"/"之间。表达式返回一个RegExp的对象。
    表达式的一般规则:
    /a/匹配字符a。
    /\?/匹配特殊字符?。特殊字符包括^, $, ? , ., /, \, [, ], {, }, (, ), +, *.
    .匹配任意字符,例如/a./匹配ab和ac。
    /[ab]c/匹配ac和bc,[]之间代表范围。例如:/[a-z]/ , /[a-zA-Z0-9]/。
    /[^a-zA-Z0-9]/匹配不在该范围内的字符串。
    /[\d]/代表任意数字,/[\w]/代表任意字母,数字或者_,/[\s]/代表空白字符,包括空格,TAB和换行。
    /[\D]/,/[\W]/,/[\S]/均为上述的否定情况。

    关于正则其它用法,请参照《watir技术集锦》
    5.7. 最后攻略

    总之,对于对象识别与操作,要借助于上述文档中的, 灵活运用autoit, xpath与异常对象操作方法。对于watir不支持的windows控件,想到第一个方法,就是采用第三方autoit技术,来模拟键盘或鼠标操作。
    对于操作web对象,watir不支持特殊tag,除了扩展其底层代码外,只能深深研究一下xpath了.
    最后,再搞不定,就只能到watir group里咨询高人了,呵呵。

    尚没有碰到其它更好方法。。。

491/3123>
Open Toolbar