发布新日志

  • (ZT)pywinauto GUI自动化测试工具

    2009-07-23 23:33:09

    pywinauto is a set of python modules to automate the Microsoft Windows GUI. At it's simplest it allows you to send mouse and keyboard actions to windows dialogs and controls.

         pywinauto是一些用于自动化测试微软Windows图形界面的模块的集合。它可以允许你很容易的发送鼠标、键盘动作给Windows的对话框和控件。

        地址:http://www.openqa.org/pywinauto/


  • (ZT)White:一个新的Windows界面开发测试框架

    2009-07-23 23:27:29

    一种新的界面测试框架发布了,名为White。White与WatiN类似,它封装了微软的UIAutomation库和Window消息,可以用于测试包括Win32,WinForm, WPF和SWT(java)在内的软件。ThoughtWorks的Vivek Singh是该项目的Leader,他已将White放在了CodePlex上。White具有面向对象的API,很容易来控制一个应用,它也可以与xUnit.Net,MbUnit,NUnit,MSTest这样的测试框架结合使用,甚至Fit.Net也可以。

    Ben Hall就如何使用White写了一篇非常好的教程,该教程以示例清晰地说明White与WatiN和Selenium何其相似。

    Hello World Image

    第一个按钮只有一个非常简单的动作,即当你点击它时,它的名称会改为“Hello World!!”。其测试代码如下:

    [Test]
    public void ButtonClickable_btnClick1_ChangesText()
    {
        Application application = Application.Launch(path);
        Window window = application.GetWindow("White Hello World", InitializeOption.NoCache);

        Button button = window.Get<button>("btnClick1");   #1
        //Moves the mouse to click the button</button>

          button.Click();                   #2
        Assert.AreEqual("Hello World!!", button.Name);       #3
    }

    #1  Using the Get method, we can give it the type and name of the control we want to access.
    #2  We can then call the Click method which will move the mouse cursor over to the button and click it.
    #3  We can then verify that the action was correctly performed, in this case the Name has changed.

    Ben还展示它的其它方面,例如根据可见文字搜索控件,未处理的异常,消息框,以及测试的可读性和非常有用的辅助工具UISpy。该教程还对White给予了较高评价。

    …这个框架给我留下非常深刻的印象。尽管还缺少一些很好的特性(译者注:比如无法优雅地测试Outlook中的Toolbar),但希望它们会不断被追加进来。事实上,这个框架使用了多种不同的UI技术,这意味着你不用担心用什么来写你的界面测试,也不用考虑你的界面是否使用了不同的技术。

    查看英文原文:White: A New Windows UI Developer Testing Framework
  • (ZT)利用Jscrīpt进行简单的GUI自动化测试

    2009-07-23 23:25:24

    假设你被派往非洲出差,负责测试那边的一个软件系统,没有网络,你的准备也不够充分,居然忘了带上你经常使用的测试工具。(哈哈,谁会碰到这种倒霉事情?!)测试过程中需要重复的GUI操作,你非常后悔没有把你的QTP带上!

            这时候,可能Jscrīpt可以救你一把,哈哈。因为只需要一个记事本就可以编写你的Jscrīpt脚本,编写完后就可以马上运行(Jscrīpt脚本通过windows的脚本宿主来执行)。

            Jscrīpt提供SendKeys方法,可用于将一个或多个键击发送到活动窗口。要想使用SendKeys方法,必须先创建WshShell对象。创建方法如下:
    WshShell = Wscrīpt.CreateObject("Wscrīpt.Shell");

            然后我们就可以利用WshShell对象来启动我们需要测试的应用程序,例如,下面脚本启动记事本:
    WshShell.Run("notepad");

            启动时可同时指定窗口出现时的样式,例如,下面脚本启动记事本,并把它最大化:
    WshShell.Run("notepad",3);

            启动完应用程序后最好能先调用一下AppActivate方法,确保应用程序的窗口被激活。例如:
    WshShell.AppActivate("记事本");

            窗体出现后,我们就可以通过发送按键给窗口来操作应用程序的功能了,例如,下面脚本在记事本输入一串字符:
    WshShell.SendKeys("ABCD...");

            除了发送字符和数字,SendKeys方法还能发送组合功能键,例如使用TAB键用于在不同的按钮之间移动,Enter键用于按下按钮,组合ALT+F来关闭窗口等,这样来达到操作应用程序功能的目的(只要应用程序能相对完整地支持键盘操作、快捷键、TAB键的操作)。

            例如,下面脚本通过组合ALT+O+F键调出记事本的字体设置窗口:
    WshShell.SendKeys("%OF");

            需要注意的是,有些GUI的界面响应速度会比较慢,因此在各操作之间最好能插入时间缓冲,Jscrīpt通过Sleep方法来实现:
    Wscrīpt.Sleep(100);

            当然,前面所说的不能说是自动化测试,因为它只是把某些手工操作自动化而已,缺乏对结果的验证。但是在某些情况下还是有它的用武之地的,人生无常,搞不好真的会出现开头的一幕。

  • [转]使用Tcl扩展包cwind进行界面自动化测试

    2009-07-23 23:17:34

    cwind是一个控制界面操作的Tcl扩展包,它可以模拟键盘、鼠标的操作,捕获界面信息,控制界面窗口等,类似于QARUN等软件,通过cwind库可以利用tcl脚本方便的实现QARUN的功能,因此可以用于各种GUI测试。

    cwind扩展包命令介绍:

    to simulate a left click on the mouse
    ::cwind::lclick

    to simulate a right click on the mouse
    ::cwind::rclick

    to simulate a middle click on the mouse
    ::cwind::mclick

    to set the mouse position
    ::cwind::setpos
    where the starting position (0 0) is the upper left corner

    to get the mouse position
    ::cwind::getpos

    to get the cursor postion based on the position of the foreground window
    ::cwind::getwpos

    to set the cursor postion based on the position of the foreground window
    ::cwind::setwpos

    In version 1.3

    to send a message to the foreground window.
    ::cwind::sendmessage ?? ??
    Message name is the windows's message to be sent.
    Wparam and lparam are additional value.

    to post a message to the foreground window.
    ::cwind::postmessage ?? ??
    Message name is the windows's message to be posted.
    Wparam and lparam are additional value.

    In version 1.2

    I've expanded the specification of some commands for MDI.

    to put in active a window.
    ::cwind::show ?-exact?
    Search into the list of active window's name and set in foreground this window.
    Window's name is treated as a glob-style. pattern.
    Window's name is specified in list form,
    The first element is a parent window name and the optional second element is a MDI child window name.

    to get the status of a window (Maximized, Minimized or Normal).
    ::cwind::state ?-exact?
    Window's name is treated as a glob-style. pattern.
    Window's name is specified in list form,
    The first element is a parent window name and the optional second element is a MDI child window name.

    to have a list of all opened windows.
    ::cwind::wlist ?-exact? ??
    If Window's name is omitted, Will show you a Tcl list with all the window's name.
    If Window's name is specified, Will show you a Tcl list with all the MDI child window's name.
    Window's name is treated as a glob-style. pattern.

    In version 1.1

    Due to confilcts with the Tcl command "list",
    I've renamed the command ::cwind::list to ::cwind::wlist.
    ::cwind::wlist

    to get the status of a window (Maximized, Minimized or Normal).
    ::cwind::state ?-exact?
    Window's name is treated as a glob-style. pattern.

    to restore the foreground window at the original size.
    ::cwind::restore

    to minimize the foreground window.
    ::cwind::minimize

    to maximize the foreground window.
    ::cwind::maximize

    to minimize all the windows.
    ::cwind::minimizeAll

    to wait a specific window on the foreground.
    ::cwind::waitwind ??
    Max wait is in seconds and the default value is 5.
    Window's name is treated as a glob-style. pattern.

    In version 1.0

    to send a text to the foreground window.
    ::cwind::send ...
    Send the arguments, separated by spaces.
    If you want send the spaces, enclose your text into { and }.

    to put in active a window.
    ::cwind::show ?-exact?
    Search into the list of active window's name and set in foreground this window.
    Window's name is treated as a glob-style. pattern.

    to get the active window name.
    ::cwind::gettext
    Get the test of the foreground window.

    to get the content of the clipboard.
    ::cwind::getcb

    to put strings into the clipboard.
    ::cwind::putcb

    to have a list of all opened windows.
    ::cwind::list
    Will show you a Tcl list with all the window's name.

    to set the sleep time.
    ::cwind::sleeptime ??
    Time is to ask to the system to wait before each character sent.
    A sort of delay in milliseconds.

    一些特殊键的用法:

    如果要使用像ctrl + c这样的特殊键,必须用下面的字符串序列来表示

    "|CTRL+| c |CTRL-|"

    特殊键的名字对应关系如下:

    "ALT+" press ALT
    "ALT-" release ALT
    "ALTL+" press left ALT key
    "ALTL-" release left ALT key
    "ALTR+" press right ALT key
    "ALTR-" release right ALT key
    
    "CTRL+" press CTRL
    "CTRL-" release CTRL
    "CTRLL+" press left CTRL key
    "CTRLL-" release left CTRL key
    "CTRLR+" press right CTRL key
    "CTRLR-" release right CTRL key
    
    "SHIFT+" press SHIFT
    "SHIFT-" release SHIFT
    "SHIFTL+" press left SHIFT key
    "SHIFTL-" release left SHIFT key
    "SHIFTR+" press right SHIFT key
    "SHIFTR-" release right SHIFT key
    
    "TAB" press the tabulation key
    "RET" press the return key
    "ESC" press the escape key
    
    "BACK" press the backward key
    "DEL" press the delete key
    "INS" press the insert key
    "HELP" press the help key
    
    "LEFT" send the cursor to the left
    "RIGHT" send the cursor to the right
    "UP" send the cursor to up
    "DOWN" send the cursor to down
    "PGUP" press the page up key
    "PGDN" press the page down key
    "HOME" press the home key
    "END" press the end key
    
    "F1" press the function key F1
    "F2" press the function key F2
    "F3" press the function key F3
    "F4" press the function key F4
    "F5" press the function key F5
    "F6" press the function key F6
    "F7" press the function key F7
    "F8" press the function key F8
    "F9" press the function key F9
    "F10" press the function key F10
    "F11" press the function key F11
    "F12" press the function key F12
    
    "NUM0" press the 0 on the key pad
    "NUM1" press the 1 on the key pad
    "NUM2" press the 2 on the key pad
    "NUM3" press the 3 on the key pad
    "NUM4" press the 4 on the key pad
    "NUM5" press the 5 on the key pad
    "NUM6" press the 6 on the key pad
    "NUM7" press the 7 on the key pad
    "NUM8" press the 8 on the key pad
    "NUM9" press the 9 on the key pad
    
    "NUM*" press the * on the key pad
    "NUM+" press the + on the key pad
    "NUM-" press the - on the key pad
    "NUM," press the , on the key pad
    "NUM/" press the / on the key pad
    
    "SNAP" press the print key
    "APPS" press the application key
    "KANJI" press the kanji key
    "CONV" press the convert key
    "NCONV" press the nonconvert key
    

    下面是一段演示程序,演示了打开一个记事本,输入hello world,打开about窗口,然后拷贝窗口到剪贴板,打开画笔,把界面抓图复制到画图程序。下面程序中使用的窗口名是按照英文操作系统的,对于中文操作系统,需要修改其中的窗口名,例如*WordPad修改为记事本的窗口名,*Paint修改为画笔的中文窗口名。

    package require cwind
    
    exec $env(COMSPEC) /c start wordpad.exe &
    ::cwind::waitwind {*WordPad} 10
    ::cwind::send {Hello World!} |RET|
    after 1000
    ::cwind::send |CTRL+| a |CTRL-|
    after 1000
    ::cwind::send |CTRL+| c |CTRL-|
    after 1000
    set clip [::cwind::getcb]
    after 1000
    ::cwind::send |END| |CTRL+| v |CTRL-|
    after 1000
    ::cwind::send |ALT+| h |ALT-| a
    after 1000
    ::cwind::send |ALT+| |SNAP| |ALT-|
    
    exec $env(COMSPEC) /c start mspaint.exe &
    ::cwind::waitwind {*Paint} 10
    ::cwind::send |ALT+| e |ALT-| p
    
    exit
    
    =================================
    参考资料   http://blog.csdn.net/oceanheart/archive/2008/05/24/2476874.aspx
     
  • watir 操作robot表格

    2009-07-20 15:58:03

    如何选中第2行(任务号=165)的check_box?

    下面是解决方案,测试通过

    def get_table(tlist,column,match_value)
      begin
        tnums=tlist.length
        for i in (1..tnums)
          tone=tlist[i]
          tone_rows=tone.row_count
          begin
            if tone_rows>=1 then
              tr=tone.[](1)
              td = tr.[](column)
              if td.innerText.match(match_value) then
                #puts "found!"
                return tone
              else
                #puts td.innerText
              end
            end
          rescue
            next
          end
        end
      end
    end

    def get_table_tr_by_match_value(table,column,match_value)
       begin
        rows = table.row_count
        for i in (1..rows)
          tr = table.[](i)
          td = tr.[](column)
          if td.innerText.match(match_value) then
            return tr   #当匹配到时,就返回tr
            break
          end
        end
      rescue
        #    capture_screen
      end
    end
     
     
    $ie=Watir::IE.new
    $ie.goto('http://172.19.65.99:9999')
    $ie.text_field(:name,"userid").set("10008")
    $ie.text_field(:name,"password").set("1111")
    $ie.button(:name,"submitb").click
    $ie.frame("leftFrame").link(:text,"执行任务").click
    $ie.frame("mainFrame").button(:name,"submitSelect").click
    puts $ie.frame("mainFrame").tables.length
    table = get_table($ie.frame("mainFrame").tables,4,"应用程序")
    tr = get_table_tr_by_match_value(table,4,"ACCOUNTING")
    tr.checkbox(:name,"h_Id").set
    exit

  • (ZT)Simple Watir/Ajax examples

    2009-07-15 23:15:19

    require 'watir'
    require 'test/unit'

    # Quick example of Ajax examples using Watir, should work with versions
    # 1.5.1.1148 and above.

    class Ajax_Example < Test::Unit::TestCase
      include Watir

      def test_scriptaculous_autocompleter
        browser = Browser.start('http://demo.script.aculo.us/ajax/autocompleter')
        browser.text_field(:id, 'contact_name').set('al')

        # need to fire a key press event after setting the text since the js is handling
        # keypress events
        browser.text_field(:id, 'contact_name').fire_event('onkeypress')  

        # the li/lis tags are available in watir 1.5.1
        wait_until {browser.div(:id, 'contact_name_auto_complete').lis.length > 0}
        puts browser.div(:id, 'contact_name_auto_complete').lis.length
        puts browser.div(:id, 'contact_name_auto_complete').li(:index, 5).text
        browser.div(:id, 'contact_name_auto_complete').li(:text, 'Alan Jochen').click
    end
    end
  • [ZT]Watir对WEB的操作

    2009-07-15 23:08:31

    与网页交互(Interacting With a Web Page)
    当使用Watir开发测试脚本的时候,通过给网页上的对象发送消息来与之交互。

    Watir 语法(Web Application Testing in Ruby)

    # watir的安装
    watie的安装请查看 -> Ruby library的安装

    # 使用Watir工具,需要在脚本中加上
    require 'watir'

    # 创建一个IE的实例
    ie = Watir::IE.new
    或者在创建的同时直接转到页面
    ie = Watir::IE.start('http://www.text.com/')
    Watir使用start方法同时创建一个浏览器实例并转到一个页面。
    IE浏览速度
    ie.speed = :fast
    ie.speed = :slow

    # 页面导航
    ie.goto('http://www.text.com/')
    注: ie.goto还可以运行javascript的代码如: ie.goto("javascript. ie.document.write("Hello World");")

    # 取得当前网页的网址
    ie.url

    # 点击超链接
    ie.link(:text , "Pickaxe").click
    ie.link(:href, /http:\/\/pragmaticprogrammer\.com/).click
    ie.link(:name => 'foo', :index => 1).click

    # 超链接的uri
    ie.link(:text , "Pickaxe").href
    ie.link(:index, 1).href
    ie.link(:text => "reply", :index => 2).href

    # 超链接的文本
    ie.link(:href , /http:\/\/pragmaticprogrammer\.com/).text

    对应的HTML代码为:
    <a href='http://pragmaticprogrammer.com/titles/ruby/'>Pickaxe</a>

    # img标签
    ie.image(:name, 'image').src
    ie.image(:index, 2).src

    对应的HTML代码为:
    <img name = img src='http://pragmaticprogrammer.com/titles/ruby/top.gif'>
    <img name = img src='http://pragmaticprogrammer.com/titles/ruby/head.gif'>

    # 设置复选框
    ie.checkbox(:name, "checkme").set
    ie.checkbox(:name, "checkme", "1").set # 使用name和value属性设置复选框

    # 清除复选框
    ie.checkbox(:name, "checkme").clear
    ie.checkbox(:name, "checkme", "1").clear # 使用name和value属性清除复选框

    对应的HTML代码为:
    <input type = "checkbox" name = "checkme" value = "1">

    # 设置单选框
    ie.radio(:name, "clickme").set
    ie.radio(:name=>'clickme', :index=>2).set
    ie.radio(:name, "clickme", "1").set # 使用name和id属性设置单选框

    # 使用name属性清除单选框
    ie.radio(:name, "clickme").clear
    ie.radio(:name, "clickme", "1").clear # 使用name和id属性清除单选框

    对应的HTML代码为:
    <input type = "radio" name = "clickme" id = "1">
    <input type = "radio" name = "clickme" id = "2">

    # 设置下拉框
    ie.select_list(:name, "selectme").select('Python') # 使用text属性和值来设置下拉框
    ie.select_list(:name, "selectme").select_value('2') # 使用value属性和值来设置下拉框

    # 使用name属性和值来清除下拉框
    ie.select_list(:name, "selectme").clearSelection

    对应的HTML代码为:
    <select name = "selectme">
    <option value = 1>Ruby
    <option value = 2>Java
    <option value = 3>Python
    <option value = 4>C
    </select>

    # 文本的框设置
    ie.text_field(:name, "typeinme").set("Watir World")

    # 清空文本输入框
    ie.text_field(:name, "typeinme").clear

    对应的HTML代码为:
    <input type = "text" name = "typeinme">

    # 通过值或name属性点击button
    ie.button(:value, "Click Me").click
    ie.button(:name, "clickme").click

    对应的HTML代码为:
    <input type = "button" name = "clickme" value = "Click Me">

    # 通过值或name属性点击Submit
    ie.button(:value, "Submit").click
    ie.button(:type, "Submit").click
    ie.button(:name, "Submit").click

    对应的HTML代码为:
    <form. action = "submit" name = "submitform" method="post">
    <input type = "submit" value = "Submit">
    </form>

    # 表单中的图片按钮
    ie.button(:name, "doit").click

    对应的HTML代码为:
    <form. action = "submit" name = "doitform" method="post">
    <input type="image" src = "images/doit.gif" name = "doit">
    </form>

    # 没有按钮的表单
    ie.form(:name, "loginform").submit # 通过name,action以及method属性来提交表单
    ie.form(:action, "login").submit
    对应的HTML代码为:
    <form. action = "login" name = "loginform" method="get">
    <input name="username" type="text">
    </form>

    # 框架
    ie.show_frames可以打印出当前页面框架的数量和名称
    Watir允许通过名称属性来访问框架,如ie.frame("menu")
    如果要访问menu框架中的一个超链接,可以
    ie.frame("menu").link(:text, "Click Menu Item").click

    # 嵌套框架
    ie.frame(:name, "frame1").form(:name, 'form1')

    # 新窗口
    一些Web应用会弹出新窗口或打开一个新窗口,可以使用attach方法来访问并控制新窗口。通过标示新窗口的URL或者title来访问。
    ie2 = Watir::IE.attach(:url, 'http://www.text.com/')
    ie3 = Watir::IE.attach(:title, 'Test New Window')
    也可以使用正则表达式
    ie4 = Watir::IE.attach(:title, /Test New/)
    注意:不要把新窗口分配到你的ie变量,最好给新窗口一个不同的名字

    # 访问Table元素:
    t = $ie.table(:id,"data")
    t = Table.new($ie,:id,"data")
    t = $ie.table[1]

    # tr,td元素
    tr = ie.row(:id,"title")
    tr = TableRow.new(ie,:id,"title")

    td = ie.cell(:id,"name")
    td = TableCell.new(ie,:id,"name")

    # Watir中Table,TableBody,TableRow,TableCell这几个类,都提供了一个索引方法"[](index)"来定位其下一层的子元素对象,该方法为实例方法,"index"为传入的参数,索引值从1开始,而非从0开始。
    用法如下:
    以table的第一行,第一个元素为例:
    tr1 = t.[](1)
    td1 = tr1.[](1)
    也可以连续访问:td1 = t.[](1).[](1)
    如果td中还有其他元素,可以通过td的实例方法直接访问,以checkbox为例:
    cb = td1.checkbox(:id,'navigate_id').click

    对于以上所提到的对象,都是从Element继承而来,所以click,enabled?,exists?,fireEvent,flash,focus等方法都直接可以使用。
    如果你的td元素定位准确了,且鼠标响应事件没有错误的话,那么应该能看到点击后的效果。
    建议多查一下Watir的API Reference http://wtr.rubyforge.org/rdoc/

    代码如下:
    t = ie.table(:id,"CoolMenu2menutable")
    td_logout=t.[](1).[](16)

    先找到Table,再索引TR,再索引到TD

    # 运行Ruby时不显示browser方法
    运行Ruby程序文件时在后面加 "-b"
    ex:
    test.rb -b
    也可以做成.bat文件
    ex: test.bat
    ruby.exe test.rb -b

    # 获取隐含对象值
    <INPUT type=hidden value="您的Email" name="field1">
    方法:values = ie.hidden(:name, 'field1').value

    # 获取窗口对象
    方法1: ie2 = Watir::IE.attach(:url,'http://www.google.cn/')   #根据URL获取
    方法2: ie3 = Watir::IE.attach(:title,'Google')                #根据窗口标题获
    方法3: ie4 = Watir::IE.attach(:title, /google.cn/)              #正则表达式匹配获取

    转自: htt p://www.javaeye.com/topic/299743

  • watir操作table

    2009-07-15 22:54:41

    有这样的表格:

    table

    这里,我们需要根据菜单名称列的文字来操作指定行的操作,如根据“ruby自动化测试菜单名称”这几个文字来操作这一行选择复选框,操作编辑功能等。

    编写ruby脚本的思路:

    1) 首先利用watir处理表格的功能,得到指定的table

    2)  其次,对这个table第几列进行循环检测,如果匹配到指定的文件,那么返回这个Table的tr对象

    3)根据这个返回的tr对象,就可以进行指定的操作了

    基础方法脚本编写:

    根据这个思路,我们设计两个方法:

    =begin
        功能描述: 得到指定的table
        参数描述: table_sym_type:属性类型;table_sym_name:属性值;
        返回类型: 返回指定的table对象
        调用方法:get_table(ie,"id","yui-dt0-bodytable")
    =end
    def get_table(ie,table_sym_type,table_sym_name)
      return ie.table(table_sym_type.to_s,table_sym_name.to_s)
    end
    =begin
        功能描述: 得到指定的table中的匹配行
        参数描述: table:指定的talbe,column:需要匹配的列,match_value:需要匹配的值
        返回类型: 返回指定的tr(行)
        调用方法: get_table_tr_by_match_value(table,3,"ruby自动化测试菜单名称")
    =end
    def get_table_tr_by_match_value(table,column,match_value)
         begin
          rows = table.row_count
          for i in (1..rows)
            tr = table.[](i)
            td = tr.[](column)
            if td.innerText.match(match_value) then
              return tr   #当匹配到时,就返回tr
              break
            end
          end
        rescue
          #    capture_screen
        end
    end

    自动化实行方法编写

    有了这些基础方法后,就可以直接使用,来实行自动化脚本了

    require ‘watir’

    ie = Watir::IE.attach(:url,/matchurl/)

    table = get_table(ie,"id","yui-dt0-bodytable")

    tr = get_table_tr_by_match_value(table,3,"ruby自动化测试菜单名称")

    tr.check_box(:name,nameValue).set

    tr.link(:text,textvalue).click

  • watir 在ROBOT中的应用

    2009-07-13 20:32:13

    下面是我写的一段ruby程序,主要用于枚举页面中的控件元素,来组装数据模板

    def show_robot(ieone)
          puts "-----------Objects in  page 1-------------"
          doc = ieone.document
          s = ""
          props=["text", "name" ,"value","href"]
          doc.all.each do |n|
              begin
                  obj_type = n.invoke("type").to_s
                  obj_opt = ""
                  if obj_type != ""
                      case  obj_type
                        when "submit"
                          obj_opt = "click"
                        when "button"
                          obj_opt = "click"
                        when "text"
                          obj_opt = "set"
                        when "select-one"
                          #puts ieone.select_list(:name, n.invoke("name")).getAllContents
                          puts "begin..."
                          #sl = n.invoke("innerText")
                          sl = ieone.select_list(:name, n.invoke("name")).getAllContents
                          sl.each do |sl_one|
                            begin
                              puts sl_one
                              puts ieone.select_list(:name,n.invoke("name")).option(:text, sl_one).value()
                            rescue
                              next
                            end
                          end
                          puts "end ..."
                        else
                          obj_opt = "oth"
                      end
                      s=s+"TAG=WEBID\t"+n.invoke("type").to_s.ljust(16) + "\t#{obj_opt}\t"
                  else
                      s=s+n.invoke("type").to_s.ljust(16)
                      #p = n.invoke(prop)
                      #       temp_var = "#{p}".to_s.ljust(printsize)
                      #continue
                  end
              rescue
                  next
              end
              props.each do |prop|
                  begin
                      p = n.invoke(prop)
                      s =s+ "\t" + "#{prop}=#{p}".to_s.ljust(18)
                  rescue
                      # this object probably doesnt have this property
                  end
              end
              s=s+"\n"
          end
          puts s+"\n\n\n"
      end 

  • 关于ROBOT两个问题讨论

    2009-07-12 18:12:12

    网友bsbolg提的问题:
      看了LZ的UT-ROBOT自动化测试工具的介绍,感觉非常的神奇,但依然有些不解之处,望LZ有空的时候一一解答, 谢谢!
    1.无需编写脚本即可生成测试用例,这个很神奇,请问测试人员在开始测试之前是否要按照ROBOT识别的格式编写手工脚本,然后由UT-ROBOT自动识别后编译执行呢?
    2. 从上传的演示视频上能看出是对交易后的数据库的数据准确性进行测试,同时还能看到有些在IE上操作的代码,请问LZ,那些操作IE代码是否也是自动生成的,是如何自动生成的,需要测试人员预先以某种方式告诉UT-Robot吗?是否能上传个视频详细演示一下Web GUI方面的测试呢?
     
     
    我的回答如下:
       在回答你的问题之前,我先说一下我为什么不采用成熟的QTP或者IBM ROBOT架构,原因有几点:第一,在我们涉及的测试范围中WEB测试只是比较小的一部分,我们有大量的后台应用和业务流程要测试,QTP一方面实在太复杂了,我们能用到东西太少,另一方面而我们需要用到大部分功能的QTP又不支持;第二,QTP的数据驱动模型在我看来并不强大,缺少了关系型的结构,在产生CASE方面实在不敢恭维(或许是我对QTP的认识有限);第三,QTP的对象库太复杂,CASE管理缺少继承性;第四,对于做了很多年测试的人来说,自动化最重要的是想法,我们没有办法根据我们的需要去修改QTP;第五,我们的团队曾经有不少人前仆后继的去学习QTP,或者尝试去做基于QTP的管理架构(在51TESTING也看到过很多类似这种架构的讨论),都是仅仅限于WEB的测试,到最后都没有继续发展下去.....还有很多很多理由让我们自己去做架构。
        U-ROBOT设计的初衷是要减少测试人员的工作量,我们的后台架构在LINUX上,测试人员只要按照驱动数据模板去填写数据就可以,而不需要去管CASE的存储、部署、文件的管理等工作,CASE都不是事先生成的,都是在运行时根据配置临时产生的,这样对CASE的维护量就少了很多,也就是说不存在去维护几千个CASE脚本的问题。所以回头看看你提的两个问题,回答如下:
        1.请问测试人员在开始测试之前是否要按照ROBOT识别的格式编写手工脚本?
       有两种情形,第一,对于WEB测试或者是接口测试(如SOAP)测试人员不需要去编写脚本,我们把脚本的解释放在后台去完成,测试人员需要做的工作就是在前台做CASE的组合;第二,对于完全是场景驱动的应用,如呼叫测试等,则需要通过堆积木的方式拖拉组织CASE场景。
        2.同时还能看到有些在IE上操作的代码,请问LZ,那些操作IE代码是否也是自动生成的?
       我的做法是,通过程序去扫描页面上的网页元素,生成初始模板,测试人员在初始模板上进行网页元素赋值及CASE组合就可以,动态生成符合Watir语法的脚本,也就是说测试人员不需要去了解相关的语法,当然有兴趣的也可以去修改自动产生的CASE脚本。我在Linux后台开发了一个WEB Proxy,来协调前台任务与Watir的调用,从而在任务管理界面就可以去驱动WEB自动化测试。
  • ROBOT数据模型介绍

    2009-07-09 22:54:45

    下面两个截图是ROBOT的数据驱动模型,由于数据比较宽,所以分了两屏展示

     

     

  • watir autoit 应用

    2009-07-09 22:51:03

    下面文档,简单罗列了我在技术评估时,经过自己学习,加工整理,总结的文档。由于时间急促不可能涉及方方面面,但常用基础的可以先从下面开始着手。。。,

     

    如果期望成为autoIT高手,最好还是参看其help文档,国外有专门招聘auitit自动化,国内很少。

     

    1.     AUTOIT

    1.1.     AutoIT是什么?

    AutoIT是一款自由软件,现在最新版本是autoit v3.

    从此介绍上看,其诞生目的就是为了解决某些语言,像vbs and sendkeys,在操作windows gui时不稳定,或无法实现的技术提供解决方案。其主要功能是用来模拟键盘和鼠标来进行windows控件操作来实现操作自动化的目的。与我们要做的自动化相关,具体有如下特征,

    A,使用类basic语法脚本

    B,模拟键盘和鼠标操作

    C,与标准windows控件交互

    D,生成GUI

    E, com支持

    F,正则表达式支持

    G,调用外部dllwindows api

    H,独立装载,编译,运行,可打包成可执行的exe

     

    联系我们做自动化,脱离与iedocument对象的windows对象,watir就力不从心,如:上传,下载,JS写的控件/第三方非web控件alerts window, JS pop up window,几乎所有的非web, windows弹出框都是。

     

    从了解watir底层代码,其解决windows对象识别与操作没有用其它技术,就是采用autoit

    最后,从搞自动化技术角度来看,autoit是一样非常强大的利器,不使用它非常遗憾。

    因为只要在win OS上操作,不管做web、还是windows自动化都需要它帮助,在操作的稳定性

    与可能性上autoIT提供了相对较强的解决方案。

      

    1.2. AutoIT安装与部署

     

    A,下载:

    http://www.autoitscrīpt.com/autoit3/downloads.shtml

     

    b,注册:

    先下载安装,再找到AutoItX3.dll进行手工注册一下,

    注意:watir1.5. 6在安装时,其安装目录里提供的AutoItX3.dll似乎不能正常工作

     regsvr32 D:\AutoIt3\AutoItX\AutoItX3.dll

     

    c,讨论:

    http://www.autoitscrīpt.com/forum/index.php?

     

    1.3. AutoIT SPY工具

     

    A, autoIT v3 window info工具

    非常类似QTP object spy工具,拖拽到要识别的windows control对象上,

    会立即显示Title, class, Advanced(class), ID, ClassnameNN, ControlClick Coords:  

    Text等字段。这些属性对于操作windows对象,起到很好的标识作用。供autoiT中内置方法提供操作句柄与操作引用.

     

    1.4.     AutoIT scrīpt

     

    Auto IT提供一整套的脚本语法,与程序开发规范.

    提供特定的数据类型,操作符与保留字,条件语句与函数、子程序结构。

    其采用分号;作为脚本注释。

     另外也提供基于命令行的编译与运行环境,不过可以用其自带IDE: sciTE,缺点是

    不能debug.

     

    下面的操作方法,将会在watir中比较常用到,

     

    1,MsgBox(0, "My First scrīpt!", "Hello World!")

    2,TestFunc()

    Func TestFunc()
        MsgBox(0, "My Second scrīpt!", "Hello from the functions!")
    EndFunc

     

    3,WinWaitActive ( "title", ["text"], [timeout] )/WinClose("[ACTIVE]", "")

    4,ControlSend("Untitled - Notepad", "", "Edit1", "This is some text")/

    ControlClick("My Window", "", "[ID:254]")

    5,ControlFocus "title", "text", "controlID"

     6,正则StringRegExp("test","pattern"[,flag] )

     7,Send "keys" [, flag]/Sleep delay

     

     

    1.5.     应用场景

     

    更多的example请参考:autoit3\examples\helpfile\*.*

     1,下载文件

     

    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

    ie.span(:text, "导出Excel").click_no_wait

    save_file("C:\\abc.xls")

     

    有没有看到,每个autoit方法在call的时候都传入一些参数?

    我怎么知道的呢?都是从autoit sby工具获得的。。。

     

    2,点击弹出框

     

    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('Microsoft Internet Explorer', '', 1)

           #ret = WinActivate("Microsoft Internet Explorer", "")

           autoit.ControlClick("Microsoft Internet Explorer", "", "[CLASS:Button; INSTANCE:1]", 2)

           #强行点击,以使其获得focus

           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

     

     

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

    sleep(20)

     

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

     

    at_exit { Thread.kill($popup) }

     

    还有很多例子,可以以此类推,只要第1:激活,第2步:获得焦点,第3步:就可以sendkey了。

    是不是已经搞定99.999%的问题了?

     

    注意:在watir中使用autoIT,别忘记require 'win32ole'

  • 博客空间日志分类说明

    2009-07-09 22:44:59

      不少朋友对ROBOT框架比较感兴趣,于是萌生了一个想法,就是把ROBOT涉及到的技术进行了分类,把相关的技术文档与大家共享一下,也欢迎博友们提提意见和建议....
  • 我的ROBOT框架最近又增加了许多新的feature

    2009-07-09 22:19:30

       做ROBOT自动化框架已经有一段时间,感触颇深,觉得自己开发自动化平台的好处还是挺多的,最重要的一点就是可以把自己的无限想象运用到框架当中,成就感也比较多。而且最近接到其它公司和猎头的电话明显多了很多,主要还是看重了自动化经验这一块,这也算是一个bonus吧,闲话少说,还是来谈谈最近的新进展吧。

       1.采用了Ajax技术加强任务管理的人性化的交互

       2.支持功能模块的拖拉操作,通过拖拉方式来组织CASE,更加直观

       3.增强了TCL/JAVA/RUBY之间的消息通讯机制,使得WEB GUI的自动化更加强壮

       4.整合了数据模型为:头定义,函数定义,表定义,资源定义,模板数据,场景脚本,使得框架更加稳定,可以覆盖功能、数据驱动、业务场景、WEB等方面的自动化测试

       5.增加了容错机制

      

      

         

  • Java入门:深入讨论正则表达式快速入门

    2009-07-06 22:20:06

    元字符:

    /b 
    代表着单词的开头或结尾,也就是单词的分界处.如果要精确地查找hi这个单词的话,我们应该使用/bhi/b.

    .
    是另一个元字符,匹配除了换行符以外的任意字符,*同样是元字符,它指定*前边的内容可以重复任意次以使整个表达式得到匹配。


    .*
    连在一起就意味着任意数量的不包含换行的字符。

    /d
    是一个新的元字符,匹配任意的数字,0/d/d-/d/d/d/d/d/d/d/d也就是中国的电话号码.为了避免那么多烦人的重复,我们也可以这样写这个表达式:0/d{2}-/d{8}

    /s
    匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。/w匹配字母或数字或下划线或汉字。

    /b/w{6}/b 
    匹配刚好6个字母/数字的单词。

    字符转义:使用/来取消这些字符的特殊意义。因此,你应该使用/./*。当然,要查找/本身,你也得用//

      
    代码     说明
       .  
    匹配除换行符以外的任意字符
      /w  
    匹配字母或数字或下划线或汉字
      /s  
    匹配任意的空白符
      /d  
    匹配数字
      /b  
    匹配单词的开始或结束
      ^   
    匹配字符串的开始
      $   
    匹配字符串的结束

    重复:
    常用的限定符
    代码/语法  说明
       *  
    重复零次或更多次
       +  
    重复一次或更多次
       ?  
    重复零次或一次
      {n} 
    重复n
     {n,} 
    重复n次或更多次
    {n,m} 
    重复nm

    要想查找数字,字母或数字,你只需要在中括号里列出它们就行了,像[aeiou]就匹配任何一个元音字母,[.?!]匹配标点符号(.?!)

    反义:
     
    常用的反义代码
     
    代码/语法   说明
       /W   
    匹配任意不是字母,数字,下划线,汉字的字符
       /S   
    匹配任意不是空白符的字符
       /D   
    匹配任意非数字的字符
       /B   
    匹配不是单词开头或结束的位置
     [^x]   
    匹配除了x以外的任意字符
          [^aeiou]   
    匹配除了aeiou这几个字母以外的任意字符


    替换:
       
    正则表达式里的替换指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
       0/d{2}-/d{8}|0/d{3}-/d{7}
    这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(010-12345678),一种是4位区号,7位本地号(0376-2233445)
       /(0/d{2}/)[- ]?/d{8}|0/d{2}[- ]?/d{8}
    这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用替换|把这个表达式扩展成也支持4位区号的。
       /d{5}-/d{4}|/d{5}
    这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用替换时,顺序是很重要的。如果你把它改成/d{5}|/d{5}-/d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5)。原因是匹配替换时,将会从左到右地测试每个分枝条件,如果满足了某个分枝的话,就不会去管其它的替换条件了。

    分组:

    如果想要重复一个字符串又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了。
         (/d{1,3}/.){3}/d{1,3}
    是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:/d{1,3}匹配13位的数字,(/d{1,3}/.}{3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(/d{1,3})。不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址(IP地址中每个数字都不能大于255)。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4] /d|25[0-5]|[01]?/d/d?)/.){3}(2[0-4]/d|25[0-5]|[01]?/d/d?)

    后向引用:

    后向引用用于重复搜索前面某个分组匹配的文本。例如,/1代表分组1匹配的文本。难以理解?请看示例:
    /b(/w+)/b/s+/1/b
    可以用来匹配重复的单词,像go go, kitty kitty。首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(/b(/w+)/b),然后是1个或几个空白符(/s+,最后是前面匹配的那个单词(/1)

    懒惰限定符
    *? 
    重复任意次,但尽可能少重复
    +? 
    重复1次或更多次,但尽可能少重复
    ?? 
    重复0次或1次,但尽可能少重复
    {n,m}? 
    重复nm次,但尽可能少重复
    {n,}? 
    重复n次以上,但尽可能少重复

    位置指定:


    接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们用于指定一个位置,就像/b,^,$那样,因此它们也被称为零宽断言。最好还是拿例子来说明吧:

    (?=exp)
    也叫零宽先行断言,它匹配文本中的某些位置,这些位置的后面能匹配给定的后缀exp。比如/b/w+(?=ing/b),匹配以 ing结尾的单词的前面部分(除了ing以外的部分),如果在查找I'm singing while you're dancing.时,它会匹配singdanc

    (?<=exp)
    也叫零宽后行断言,它匹配文本中的某些位置,这些位置的前面能给定的前缀匹配exp。比如(?<=/bre)/w+/b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading

    假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=/d)/d{3})*/b。请仔细分析这个表达式,它可能不像你第一眼看出来的那么简单。

    下面这个例子同时使用了前缀和后缀:(?<=/s)/d+(?=/s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)

    负向位置指定:


    前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

    /b/w*q[^u]/w*/b
    匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总是匹配一个字符,所以如果q是单词的最后一个字符的话,后面的 [^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的/w+/b将会匹配下一个单词,于是/b/w*q[^u]/w*/b 就能匹配整个Iraq fighting。负向位置指定能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:/b/w*q(?!u) /w*/b

    零宽负向先行断言(?!exp),只会匹配后缀exp不存在的位置。/d{3}(?!/d)匹配三位数字,而且这三位数字的后面不能是数字。

    同理,我们可以用(?<!exp),零宽负向后行断言来查找前缀exp不存在的位置:(?<![a-z])/d{7}匹配前面不是小写字母的七位数字(实验时发现错误?注意你的区分大小写先项是否选中)

    一个更复杂的例子:(?<=<(/w+)>).*(?=)匹配不包含属性的简单HTML标签内里的内容。()指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=)。注意后缀里的//,它用到了前面提过的字符转义;/1则是一个反向引用,引用的正是捕获的第一组,前面的(/w +)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是和< /b>之间的内容(再次提醒,不包括前缀和后缀本身)

    注释:
    小括号的另一种用途是能过语法(?#comment)来包含注释。例如:2[0-4]/d(?#200-249)|25[0-5](?#250-255)|[01]?/d/d?(?#0-199)

    要包含注释的话,最好是启用忽略模式里的空白符选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。

    例如,我们可以前面的一个表达式写成这样:

          (?<=    # 
    查找前缀,但不包含它
          <(/w+)> # 
    查找尖括号括起来的字母或数字(标签)
          )       # 
    前缀结束
          .*      # 
    匹配任意文本
          (?=     # 
    查找后缀,但不包含它
            # 
    查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
          )       # 
    后缀结束


    贪婪与懒惰:
    当正则表达式中包含能接受重复的限定符(指定数量的代码,例如*, {5,12})时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

    有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

    a.*?b
    匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aabab(为什么第一个匹配是aab而不是ab?简单地说,最先开始的区配最有最大的优先权??The Match That Begins Earliest Wins)。

    5.懒惰限定符 *? 重复任意次,但尽可能少重复
    +? 
    重复1次或更多次,但尽可能少重复
    ?? 
    重复0次或1次,但尽可能少重复
    {n,m}? 
    重复nm次,但尽可能少重复
    {n,}? 
    重复n次以上,但尽可能少重复

    -------------------------------------------------------

    下面是一些常用的正则表达式:

    匹配中文字符的正则表达式: [/u4e00-/u9fa5]
    评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

    匹配双字节字符(包括汉字在内)[^/x00-/xff]
    评注:可以用来计算字符串的长度(一个双字节字符长度计2ASCII字符计1

    匹配空白行的正则表达式:/n/s*/r
    评注:可以用来删除空白行

    匹配HTML标记的正则表达式:<(/S*?)[^>]*>.*?|<.*? />
    评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

    匹配首尾空白字符的正则表达式:^/s*|/s*$
    评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

    匹配Email地址的正则表达式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
    评注:表单验证时很实用

    匹配网址URL的正则表达式:[a-zA-z]+://[^/s]*
    评注:网上流传的版本功能很有限,上面这个基本可以满足需求

    匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)^[a-zA-Z][a-zA-Z0-9_]{4,15}$
    评注:表单验证时很实用

    匹配国内电话号码:/d{3}-/d{8}|/d{4}-/d{7}
    评注:匹配形式如 0511-4405222  021-87888822

    匹配腾讯QQ号:[1-9][0-9]{4,}
    评注:腾讯QQ号从10000开始

    匹配中国邮政编码:[1-9]/d{5}(?!/d)
    评注:中国邮政编码为6位数字

    匹配身份证:/d{15}|/d{18}
    评注:中国的身份证为15位或18

    匹配ip地址:/d+/./d+/./d+/./d+
    评注:提取ip地址时有用

    匹配特定数字:
    ^[1-9]/d*$
        //匹配正整数
    ^-[1-9]/d*$ 
      //匹配负整数
    ^-?[1-9]/d*$
       //匹配整数
    ^[1-9]/d*|0$
      //匹配非负整数(正整数 + 0
    ^-[1-9]/d*|0$
       //匹配非正整数(负整数 + 0
    ^[1-9]/d*/./d*|0/./d*[1-9]/d*$
       //匹配正浮点数
    ^-([1-9]/d*/./d*|0/./d*[1-9]/d*)$
      //匹配负浮点数
    ^-?([1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0)$
      //匹配浮点数
    ^[1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0$
       //匹配非负浮点数(正浮点数 + 0
    ^(-([1-9]/d*/./d*|0/./d*[1-9]/d*))|0?/.0+|0$
      //匹配非正浮点数(负浮点数 + 0
    评注:处理大量数据时有用,具体应用时注意修正

    匹配特定字符串:
    ^[A-Za-z]+$
      //匹配由26个英文字母组成的字符串
    ^[A-Z]+$
      //匹配由26个英文字母的大写组成的字符串
    ^[a-z]+$
      //匹配由26个英文字母的小写组成的字符串
    ^[A-Za-z0-9]+$
      //匹配由数字和26个英文字母组成的字符串
    ^/w+$
      //匹配由数字、26个英文字母或者下划线组成的字符串
    评注:最基本也是最常用的一些表达式[java] 

  • JAVA正则表达式4种常用功能‏

    2009-07-06 22:18:33

    JAVA正则表达式4种常用功能 
       
      正则表达式在字符串处理上有着强大的功能,sunjdk1.4加入了对它的支持 
     
      下面简单的说下它的4种常用功能:
      
      查询:
      
    以下是代码片段:
     String str="abc efg ABC"; 
     
    String regEx="a|f"; //
    表示a
     
     Pattern p=Pattern.compile(regEx); 
     
     Matcher m=p.matcher(str); 
     
     boolean rs=m.find(); 

      
      如果str中有regEx,那么rstrue,否则为flase。如果想在查找时忽略大小写,则可以写成Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
      
      提取:
    以下是代码片段:
     String regEx=".+\(.+)$"; 
     
    String str="c:\dir1\dir2\name.txt"; 
     
     Pattern p=Pattern.compile(regEx); 
     
     Matcher m=p.matcher(str); 
     
     boolean rs=m.find(); 
     
     for(int i=1;i<=m.groupCount();i++){ 
     
     System.out.println(m.group(i)); 
     
     } 

      
      以上的执行结果为name.txt,提取的字符串储存在m.group(i)中,其中i最大值为m.groupCount();
      
      分割:
      
    以下是代码片段:
    String regEx="::"; 
     
     Pattern p=Pattern.compile(regEx); 
     
     String[] r=p.split("xd::abc::cde"); 
     
     
    执行后,r就是{"xd","abc","cde"},其实分割时还有跟简单的方法: 
     
     String str="xd::abc::cde"; 
     
     String[] r=str.split("::"); 

      
      替换(删除):
      
    以下是代码片段:
     String regEx="a+"; //
    表示一个或多个

     Pattern p=Pattern.compile(regEx); 
     
     Matcher m=p.matcher("aaabbced a ccdeaa"); 
     
     String s=m.replaceAll("A"); 
      
      结果为"Abbced A ccdeA"
      
      如果写成空串,既可达到删除的功能,比如:
      
    String s=m.replaceAll("");
      
      结果为"bbced ccde"
      
      附:
      
     \D 等於 [^0-9] 非数字 
     \s 等於 [ \t\n\x0B\f ] 空白字元 
     \S 等於 [^ \t\n\x0B\f ] 非空白字元 
     \w 等於 [a-zA-Z_0-9] 数字或是英文字 
      \W 等於 [^a-zA-Z_0-9] 非数字与英文字 
      
      表示每行的开头
      表示每行的结尾
  • java + struct + ajax‏

    2009-07-06 22:16:59

    页面部分:example.jsp
    <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <base href="<%=basePath%>">
    <title>My JSP ´example.jsp´ starting page</title>
    <meta. http-equiv="pragma" content="no-cache">
    <meta. http-equiv="cache-control" content="no-cache">
    <meta. http-equiv="expires" content="0">
    <meta. http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta. http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
    <script>

    var req;
    var which;
    function retrieveURL(url) {
    if (window.XMLHttpRequest) { // Non-IE browsers
    req = new XMLHttpRequest();
    req.onreadystatechange = processStateChange;
    try {
    req.open("GET", url, true);
    } catch (e) {
    alert(´创建对象失败´);
    }
    req.send(null);
    } else if (window.ActiveXObject) { // IE
    req = new ActiveXObject("Microsoft.XMLHTTP");
    if (req) {
    req.onreadystatechange = processStateChange;
    req.open("GET", url, true);
    req.send(null);
    }
    }
    }
    function processStateChange(){
    if (req.readyState == 4) { // Complete
    if (req.status ==200) { // OK response
    document.getElementById("test").innerHTML = req.responseText;
    } else {
    alert("Problem: " + req.statustext);
    }
    }
    }
    </script>
    </head>
    <body nload="retrieveURL(´/test/example.do´)">
    <dir id="test"></dir>
    </body>
    </html>
    action部分:ExampleAction.java
    /*
    * Generated by MyEclipse Struts
    * Template path: templates/java/JavaClass.vtl
    */
    package com.sbt.struts.action;

    import java.io.IOException;
    import java.io.PrintWriter;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.Action;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionForward;
    import org.apache.struts.action.ActionMapping;

    /**
    * MyEclipse Struts
    * Creation date: 01-11-2008
    *
    * XDoclet definition:
    * @struts.action validate="true"
    */
    public class ExampleAction extends Action {
    /*
    * Generated Methods
    */

    /**
    * Method execute
    * @param mapping
    * @param form.
    * @param request
    * @param response
    * @return ActionForward
    * @throws IOException
    */
    public ActionForward execute(ActionMapping mapping, ActionForm. form,
    HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html;charset=gbk");
    PrintWriter ut = response.getWriter();
    out.println("hello world!");
    out.flush();
    return null;
    }
    }
    config部分:struts-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

    <struts-config>
    <data-sources />
    <form-beans />
    <global-exceptions />
    <global-forwards />
    <action-mappings >
    <action path="/example" type="com.sbt.struts.action.ExampleAction" />

    </action-mappings>

    <message-resources parameter="com.sbt.struts.ApplicationResources" />
    </struts-config>

    web部分:web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
    <param-name>debug</param-name>
    <param-value>3</param-value>
    </init-param>
    <init-param>
    <param-name>detail</param-name>
    <param-value>3</param-value>
    </init-param>
    <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    </web-app>

  • javascript 动态生成表格‏

    2009-07-06 22:15:05

    转帖:来源网络
    一次翻译技术文章,本身英语水平很烂,翻译的也是自己刚开始学习的技术,所以能勉强看懂英文的话都要尽量读 原文 而不要看我的翻译,免得被误导。阅读原文
    简介
      这篇文章简单介绍了DOM 1.0一些基本而强大的方法以及如何在JavaScript中使用它们。你可以学到如何动态地创建、获取、控制和删除HTML元素。这些DOM方法同样适用于XML。所有全面支持DOM 1.0的浏览器都能很好地运行本篇的实例,比如IE5,Firefox等。
    概况 - Sample1.html
      这篇文章通过实例代码介绍DOM。请从尝试下面的HTML例子开始。它使用DOM 1的方法由JavaScript动态创建一个HTML表格。它创建一个由四个包含文本内容的单元格组成的小表格。单元格的文字内容是:“单元格是第y行第 x列”,表示单元格在表格中的行数和列数。
    <html>
    <head>
    <title>实例代码 - 使用JavaScript和DOM创建HTML表格</title>
    <script>
    function start() {
    //获取body标签
    var mybody = document.getElementsByTagName("body")[0];

    // 创建一个<table>元素和一个<tbody>元素
    mytable = document.createElement("table");
    mytablebody = document.createElement("tbody");

    //创建所有的单元格
    for(var j = 0; j < 2; j++) {
      
    // 创建一个<tr>元素
      
    mycurrent_row = document.createElement("tr");
      
    for(var i = 0; i < 2; i++) {
      
    // 创建一个<td>元素
      
    mycurrent_cell = document.createElement("td");
      
    //创建一个文本节点
      
    currenttext = document.createTextNode("单元格是第"+j+"行,第"+i+"");
      
    // 将创建的文本节点添加到<td>里
      
    mycurrent_cell.appendChild(currenttext);
      
    // 将列<td>添加到行<tr>
      
    mycurrent_row.appendChild(mycurrent_cell);
      
    }
      
    // 将行<tr>添加到<tbody>
      
    mytablebody.appendChild(mycurrent_row);
    }
    // 将<tbody>添加到<table>
    mytable.appendChild(mytablebody);
    //将<table>添加到<body>
    mybody.appendChild(mytable);
    // 将表格mytable的border属性设置为2
    mytable.setAttribute("border", "2");
    }
    </script>
    </head>
    <body onload="start()">
    </body>
    </html>
    注意我们创建各元素和文字节点的顺序:
    1.创建< table >元素
    2.创建< table >的子元素< tbody >
    3.使用一个循环来创建< tbody >的子元素< tr >
    4.分别使用循环为每一个< tr >创建子元素< tb >
    5.为每一个< tb >创建文本节点
      创建完< table >,< tbody >,< tr >,< td >元素和文本节点,我们使用相反的顺序把它们分别添加到自己的父节点。
    1.将创建的文本节点添加到< td >里
    mycurrent_cell.appendChild(currenttext);
    2.将列< td >添加到行< tr >
    mycurrent_row.appendChild(mycurrent_cell);
    3.将行< tr >添加到< tbody >
    mytablebody.appendChild(mycurrent_row);
    4.将< tbody >添加到< table >
    mytable.appendChild(mytablebody);
    5.将< table >添加到< body >
    mybody.appendChild(mytable);
    记住这个方法。当你使用W3C DOM时会经常用到它。首先,你从上向下建立元素;然后从下向上把它们添加到父节点。
    这是JavaScript代码生成的HTML:
    ...
    <table border=5>
    <tr><td>单元格是第0行,第0列</td><td>单元格是第0行,第1列</td></tr>
    <tr><td>单元格是第1行,第0列</td><td>单元格是第1行,第1列</td></tr>
    </table>
    ...
    这是代码生成的表格元素和它的子元素的DOM对象树:
    sample1-tabledom.jpg
      你只需使用少量的DOM方法就可以构造这样一个表格和他的子元素。记住要时刻谨记你将创建的构造的模型树;这样会使编写代码更加简单。在图中的< table >树里,< table >有一个子元素< tbody >。< tbody >有两个子元素。< tbody >的每个子元素(< tr >)都有两个子元素< td >。最后,每个< td >有一个子元素:一个文本节点。  
    基本的DOM方法 - Sample2.html
      getElementByTagName方法适用于文档和元素,所以文档根对象和所有的元素对象一样有 getElementByTagName 方法。你可以使用 element.getElementsByTagName(tagname) 来获取某个元素所有子元素的列表,使用标签名选择它们。
      element.getElementsByTagName 返回一个有特定标签名的子元素的列表。你可以通过调用一个item方法(传递一个index参数给它)来从这个子元素列表中获取一个元素。请注意列表第一个子元素的index为0。下一个主题继续前面的Table例子。下面这个实例更加简单,显示了一些基本的方法:
    <html>
    <head>
    <title>实例代码 - 使用JavaScript和DOM创建HTML表格</title>
    <script>
    function start() {
    // 获取一个包含所有body元素的列表(将只有一个)
    // 然后选择列表里的第一个元素
    myBody = document.getElementsByTagName("body")[0];

    // 获取body字元素中所有的p元素
    myBodyElements = myBody.getElementsByTagName("p");

    //获取p元素列表的第二个元素(索引从0开始)
    myP = myBodyElements[1];
    }
    </script>
    </head>
    <body onload="start()">
    <p>hi</p>
    <p>hello</p>
    </body>
    </html>
    在这个例子里,我们设置myP变量为表示body里第二个p元素的DOM对象。
    1.获取一个包含所有body元素的列表
    myBody = document.getElementsByTagName("body")[0];
    因为一个有效的html文档只有一个body元素,这个列表讲只有一项。我们通过使用 [0] 选取列表的第一个元素来得到它。
    2.获取blog子元素里所有的p元素
    myBodyElements = myBody.getElementsByTagName("p");
    3.选取p元素列表的第二项
    myP = myBodyElements[1];
    sample2a2.jpg
    一旦获得一个html元素的DOM对象,你就可以设置它的属性。比如,你想设置style. background color属性,只需要添加:
    myP.style.background = "rgb(255,0,0)";
    使用document.createTextNode(”..”)创建文本节点
    使用文档对象调用createTextNode方法建立你的文本节点。你只需要输入文本内容。返回值是一个表示这个文本节点的对象。
    myTextNode = document.createTextNode("world");
    以上代码创建一个文本数据是“word”的TEXT_NODE类型(文字块)节点,变量myTextNode指向这个节点对象。你需要设置这个文本节点为其他节点元素的字节点来插入这个文本到你的html页面里。
    使用appendChild(..)插入元素
    所以,通过调用myP.appendChild([node_element]),你设置这个文本节点为第二个p元素的字节点。
    myP.appendChild(myTextNode);
    测试这个例子,注意“hello”和“world”两个词是连在一起的:“helloworld”。所以在当你看到html页面时两个文本节点 hello和world看起来好像是一个节点,而实际上在这个文档模型里有两个节点。第二个节点是一个新的TEXT_NODE类型节点,并且是第二个p标签的第二个字节点。下图在文档树里显示了刚创建的文本节点。
    sample2b2.jpg
    createTextNode和appendChild是在hello和world之间添加空格的一种简单的方法。需要特别注意的是 appendChild方法将添加在最后一个子节点后面,就像world被添加到hello后面。所以如果你想在hello和world之间添加一个文本节点需要使用insertBefore方法而不是appendChild。
  • 取得table cell

    2009-07-06 22:14:03

    var countCell=document.getElementById("table").rows.item(0).cells.length;
  • JavaScript字符串函数大全‏

    2009-07-06 22:12:52

    JavaScript字符串函数大全收藏

    JS自带函数

    concat

    将两个或多个字符的文本组合起来,返回一个新的字符串。

    var a = "hello";

    var b = ",world";

    var c = a.concat(b);

    alert(c);

    //c = "hello,world"

    indexOf

    返回字符串中一个子串第一处出现的索引(从左到右搜索)。如果没有匹配项,返回 -1

    var index1 = a.indexOf("l");

    //index1 = 2

    var index2 = a.indexOf("l",3);

    //index2 = 3

    charAt

    返回指定位置的字符。

    var get_char = a.charAt(0);

    //get_char = "h"

    lastIndexOf

    返回字符串中一个子串最后一处出现的索引(从右到左搜索),如果没有匹配项,返回 -1

    var index1 = lastIndexOf('l');

    //index1 = 3

    var index2 = lastIndexOf('l',2)

    //index2 = 2

    match

    检查一个字符串匹配一个正则表达式内容,如果么有匹配返回 null

    var re = new RegExp(/^\w+$/);

    var is_alpha1 = a.match(re);

    //is_alpha1 = "hello"

    var is_alpha2 = b.match(re);

    //is_alpha2 = null

    substring

    返回字符串的一个子串,传入参数是起始位置和结束位置。

    var sub_string1 = a.substring(1);

    //sub_string1 = "ello"

    var sub_string2 = a.substring(1,4);

    //sub_string2 = "ell"

    substr

    返回字符串的一个子串,传入参数是起始位置和长度

    var sub_string1 = a.substr(1);

    //sub_string1 = "ello"

    var sub_string2 = a.substr(1,4);

    //sub_string2 = "ello"

    replace

    用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。

    var result1 = a.replace(re,"Hello");

    //result1 = "Hello"

    var result2 = b.replace(re,"Hello");

    //result2 = ",world"

    search

    执行一个正则表达式匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回 -1

    var index1 = a.search(re);

    //index1 = 0

    var index2 = b.search(re);

    //index2 = -1

    slice

    提取字符串的一部分,并返回一个新字符串(与 substring 相同)。

    var sub_string1 = a.slice(1);

    //sub_string1 = "ello"

    var sub_string2 = a.slice(1,4);

    //sub_string2 = "ell"

    split

    通过将字符串划分成子串,将一个字符串做成一个字符串数组。

    var arr1 = a.split("");

    //arr1 = [h,e,l,l,o]

    length

    返回字符串的长度,所谓字符串的长度是指其包含的字符的个数。

    var len = a.length();

    //len = 5

    toLowerCase

    将整个字符串转成小写字母。

    var lower_string = a.toLowerCase();

    //lower_string = "hello"

    toUpperCase

    将整个字符串转成大写字母。

    var upper_string = a.toUpperCase();

    //upper_string = "HELLO"

361/212>
Open Toolbar