Web自动化测试框架




一、        自动化测试的关键思路介绍

  首先,谈谈在测试自动化的情况下,带有图形界面的产品的测试用例的设计问题。因为图形界面的输出显示不是很容易做到测试结果自动化比较,所以一般的做法是把图形界面输出的部分单独建立测试用例,以手工运行。而所有非图形输出则可进行自动测试。

1.      测试用例的生成
  用编程语言或更方便的脚本语言(如VBS,Ruby等)写出短小的程序来产生大量的测试输入(包括输入数据与操作指令)。或同时也按一定的逻辑规律产生标准输出。输入与输出的文件名字按规定进行配对,以便控制自动化测试及结果核对的程序易于操作。
  这里提到的测试用例的命名问题,如果在项目的文档设计中作统一规划的话,软件产品的需求与功能的命名就应该成为后继开发过程的中间产品的命名分类依据。这样,就会为文档管理和配置管理带来很大的方便,使整个产品的开发过程变得更有条理,更符合逻辑。任何新手半途加入到开发工作中也会更容易进入状态。

2.      测试的执行写控制
  单元测试或集成测试可能多用单机运行。但对于系统测试或回归测试,就极有可能需要多台机器在网络上同时运行。记住一个这样的原则,在开发过程中的任何时候,如果你需要等候测试的运行结果的话,那就是一个缩短开发时间的机会。
  对于单个的测试运行,这样的机会在测试的设置及开始运行和结果的比对及显示。有时候,需要反复修改程序,重新汇编及重新测试。这样,每一个循环的各种手工键入的设置与指令所花费的时间,加起来就非常可观。如果能利用make或类似的软件工具来帮助,就能节省大量的时间。
  对于系统测试或回归测试这类涉及大量测试用例运行的情况,缩短时间的机会除了利用软件工具来实现自动化之外,就是怎样充分利用一切硬件资源。往往,就算是在白天的工作时间内,每台计算机的负荷都没有被充分利用。能够把大量测试用例分配到各台机器上去同时运行,就能节省大量的时间。另外,把大量的系统测试及回归测试安排到夜间及周末运行,更能提高效率。
  如果不购买商品化的工具的话,应当遵从正规的软件开发要求来开发出好的软件测试自动化工具。在实践中,许多企业自行开发的自动化工具都是利用一些现成的软件工具再加上自己写的程序而组成的。这些自己开发的工具完全是为本企业量身定做的,因此可用性非常强。同时,也能根据需要随时进行改进,而不必受制于人。当然,这就要求有一点的人力的投入。
  在设计软件自动测试工具的时候,路径控制是一个非常重要的功能。理想的使用情况是:这个工具可以在任何一个路径位置上运行,可以到任何路径位置去取得测试用例,同时也可以把测试的结果输出放到任何的路径位置上去。这样的设计,可以使不同的测试运行能够使用同一组测试用例而不至于互相干扰,也可以灵活使用硬盘的空间,并且使备份保存工作易于控制。
  同时,软件自动测试工具必须能够有办法方便地选择测试用例库中的全部或部分来运行,也必须能够自由地选择被测试的产品或中间产品作为测试对象。

3.      测试结果与标准输出的比对
  在设计测试用例的时候,必须考虑到怎样才能够易于对比测试结果和标准输出。输出数据量的多少及数据格式对比较的速度有直接影响。而另一方面,也必须考虑到输出数据与测试用例的测试目标的逻辑对应性及易读性,这将会大大有利于分析测试所发现的不吻合,也有利于测试用例的维护。
  许多时候,要写一些特殊的软件来执行测试结果与标准输出的对比工作,因为可能有部分的输出内容是不能直接对比的(比如,对运行的日期时间的记录,对运行的路径的记录,以及对测试对象的版本数据等),就要用程序进行处理。

4.      不吻合的测试结果的分析、分类、记录和通报
  上一点所谈到的,用于对测试结果与标准输出进行比对的特殊软件,往往也同时担任对不吻合的测试结果进行分析、分类、记录和通报的任务。
  “分析”是找出不吻合的地方并指出错误的可能起因。“分类”包括各种统计上的分项,例如,对应的源程序的位置,错误的严重级别(提示、警告、非失效性错误、失效性错误;或别的分类方法),新发现的还是已有记录的错误,等等。“记录”,是按分类存档。“通报”,是主动对测试的运行着及测试用例的“负责人”通报出错的信息。
  这里提到测试用例的“负责人” 的概念。是用以指定一个测试用例运行时发现的缺陷,由哪一个开发人员负责分析及修复。在设立测试用例库时,各用例均应有指定的负责人。
  最直接的通报方法是由自动测试软件发出电子邮件给测试运行者及测试用例负责人。邮件内容的详细程度可跟进需要灵活决定。

5.      总测试状况的统计,报表的产生
  这些都是自动测试工具所应有的功能。目的是提高过程管理的质量,同时节省用于产生统计数据的时间。
  产生出来的统计报表,最好是存放到一个约定的路径位置,以便任何有关人员都知道怎样查阅。同时,可按需要用电子邮件向适当的对象(如项目经理,测试经理和质量保证经理)寄出统计报表。

6.      自动测试与开发中产品每日构建的配合
  自动测试应该是整个开发过程中的一个有机部分。自动测试要依靠配置管理来提供良好的运行的环境,同时它必须要与开发中的软件的构建紧密配合。
  在开发中的产品达到一定程度的时候,就应该开始进行每日构建和测试。这种做法能使软件的开发状态得到频繁的更新,以及及早发现设计和集成的缺陷。
  为了充分利用时间与设备资源,下班之后进行自动的软件构建,紧接着进行自动测试,是一个非常行之有效的方法。如果安排的好,到第二天上班时,测试结果就已经在个人的电子邮箱里面了,等待着新的一天的开发工作。

二、        编码集成介绍

1.      Ruby的由来
  松本行弘(Matz)是日本一家开源软件公司的程序员,有15年的编程经验。在工作中,他希望有一种比Perl强大,比Python更面向对象的语言。从1993年2月,他开始设计一个全新的自己的语言,1994年12月发布了第一个alpha版本,并且将这种新语言定名为Ruby(红宝石)。发展到现在,最新稳定的版本是Ruby1.9.2.

2.      Ruby的特性
  计算机编程语言的发展总是与飞速发展的世界息息相关的,Ruby是为了适应变化、提高和完善编程艺术而出现的。
【1】完全开源。
【2】多平台:Ruby可以运行在Linux, UNIX, Windows, MS-DOS,BeOS, OS/2..
【3】多线程:线程就是指在一个程序中处理若干控制流的功能。与OS提供的进程不同的是,线程可以共享内存空间。
【4】完全面向对象。
【5】不需要内存管理:具有垃圾回收(Garbage Collect,GC)功能,能自动回收不再使用的对象。
【6】解释执行:其程序无需编译即可轻松执行。
【7】功能强大的字符串操作/正则表达式。
【8】具有异常处理功能。
【9】可以直接访问OS:Ruby可以使用UNIX的绝大部分的系统调用。单独使用Ruby也可以进行系统编程。
【10】动态类型语言:Ruby的变量没有类型,因此不必为类型匹配而烦恼。
【11】动态语言:程序运行中,可以加入熟悉,行为,也可以重写方法。
【12】支持操作符重写。
【13】支持无限精度的数字。
【14】丰富的库函数。
【15】用模块进行混合插入(Max-in):Ruby舍弃了多重继承,但拥有混合插入功能。使用模块来超越类的界限来共享数据和方法等。
【16】语法简单:它是脚本语言,没有指针,学习曲线比较低。
  总结来说,Ruby吸取了perl的正则表达式,python的简单性可读性,smalltalk的纯面向对象语法和单继承,LISP的无穷嵌套的语法,java的线程….

3.      Watir介绍
  Watir封装了对web页面元素识别的机制,测试者可以利用Ruby在这个框架下根据对象的属性识别,而后写Ruby代码控制测试逻辑,加入检查点等等以达到自动化测试目的,并且有可以随意自由定制框架和测试逻辑的优点。

4.      下载和安装ruby + water
【1】首先访问ruby官方网站:http://www.ruby-lang.org/zh_CN/downloads/
【2】访问Watir官方网站:http://wtr.rubyforge.org/install.html 【3】按照网站上的描述进行如下操作:
 1)必须先完成Ruby的安装;
 2)打开“运行”,输入cmd进入控制台;
 3)输入下面代码:
    gem update –system
     gem install water
  4)等待安装完成,如果安装失败,需要手工添加类库文件:
    http://rubyforge.org/frs/?group_id=126    下载最新的rubygems-xxx.zip版本。
 注: 为了让Watir认识中文并操作文件上传,需要做下面的修改:
    首先修改C:\ruby\lib\ruby\gems\1.9\gems\watir-xxx\watir\input_elements.rb文件,找到FileField类下的set方法,把原来的替换成
    system(“rubyw –e \”require ‘win32ole’;@autoit=WIN32OLE.new(‘AutoItX3.Control’);waitresult=@autoit.WinWait’选择文件’,”,15;sleep 1;ifwaitresult==1\”–e\”@autoit.ControlSetText’选择文件’,”,’Edit1’,’#’;@autoit.ControlSend’选择文件’,”,’Button2’,”;\” –e\”end\””)

5.      开始第一个小程序
【1】安装开发工具,此次选择eclipse,加上RDT插件org.rubypeople.rdt-xxxx.zip
【2】eclipse下载地址:http://www.eclipse.org/downloads/
【3】RDT下载地址:http://update1.aptana.org/rdt/3.2/index.html 【4】安装好eclipse之后,打开eclipse面板,点Help ->Software Updates -> Available Software-> Add Site -> Archive-> 选中下载好的org.rubypeople.rdt-xxx.zip-> 点OK按钮。
准备好开发工具后,让我们进入例子:
  模拟打开Google的主页,然后在Google唯一的那个文本框内输入”pickaxe”这个字符串,然后按下“Google搜索”按钮,之后验证搜索结果的页面中是否包含了“ProgrammingRuby”这个字符串,并跟进结果使用puts函数在屏幕上打印不同的信息。
  代码如下:
require 'watir' # the watircontroller
# open the IEbrowser
ie = Watir::IE.new
# Step 1: go to the test site:http://www.google.com
ie.goto(http://www.google.com)
# Step 2: enter 'pickaxe' inthe search text field
ie.text_field(:name,"q").set("pickaxe") # q is the name of thesearch
# Step 3: click the'Google Search'button
ie.button(:name,"btnG").click #"btnG" is the name of the Searchbutton
# Actual Result: Checkthat the 'Programming Ruby' link appears on the resultspage
if ie.contains_text("Programming Ruby")
puts "Test Passed. Found the test string:'Programming Ruby'. Actual result match ExpectedResults."
else
puts "Test Failed! Could not find:'Programming Ruby'"
end
# End of test: Googlesearch

6.      Ruby语法快览
【1】注释与分行:
   # 从#开头到行尾是单行注释;
   =begin
    xxxx
    =end 是多行注释,这也是Ruby的内嵌文档(Rdoc)注释。Rdoc是内嵌在ruby代码之中的,可以转换为html文档说明。
   Ruby中用分号“;”来表示一个语句的结束。一行如果有多个语句,每个语句用分号隔开,而最后一个语句可以省略分号。换行符表示一行结束。如果语句太长,可以用“\”连接下一行。
【2】分隔符:
  ;分号:用来分隔一行中的多个语句。
  () 圆括号:提高优先级;定义方法时容纳参数列表;
    空格:分隔字符:在可省略()的地方,代替()
   ,逗号:隔开多个参数;
  .  点:将对象与它的方法隔开;
  ::紧连的两个冒号:域作用符,将模块(类)与它的常量隔开。
【3】关键字:
  模块定义:module
   类定义:class
   方法定义:def ,undef
   检查类型:defined?
  条件语句:if ,then ,else ,elsif ,case ,when ,unless
   循环语句:for ,in ,while ,until ,next ,break ,do ,redo ,retry ,yield
   逻辑判断:not ,and ,or
   逻辑值和空值:true ,false ,nil
   异常处理:rescue ,ensure
   对象引用:super ,self
   块的起始:begin/end
   嵌入模块:BEGIN ,END
   文件相关:__FILE__ , __LINE__
   方法返回:return
   别名:alias
【4】运算符:优先级由高到低
  [][]=      数组下标数组元素赋值
  **       乘幂
  ! ~ + -    非 位非 一元加 负号
  * / %     乘除 模
  + -        加减
  >><<     右移左移
  &        位与
  ^ |       位异或 位或
  <= < >>=  小于等于 小于 大于 大于等于
  <=> == === =~ != !~ 各种相等判断
  &&       短路与
  ||        短路或
  .. …       区间的开始点到结束点
  ?:        三元条件运算符
  = %= ~= /= -= += |= &=>>= <<=*= &&= ||= **=  各种赋值
  defined?   检查类型
  not       逻辑非
  or and     逻辑或 逻辑与
【5】标识名和变量的作用域
  Ruby使用一个约定来帮助它区别一个名字的用法:名字前面的第一个字符表明这个名字的用法。局部变量、方法参数和方法名称应该用一个小写字母开头或者用一个下划线开头;全局变量用美元符作为前缀$;而实例变量用@开头;类变量用@@开头;类名、模块名和常量应该用大写字母开头。
  词首字母后面可以是字母、数字和下划线的任意组合;@后面不可以直接跟数字。
【6】数据类型:
  Ruby的数据类型有数字,字符串,数组,哈希表,区间,正则表达式。
  数字分为整数型和浮点型。浮点型数据小数点后必须跟数字。
  字符串是在单引号、双引号之间的代码;
  数组的小标从0开始。数组的每个元素可以是不同的类型。
  区间 .. …
【7】赋值和条件运算符:
  Ruby基本的赋值用“=”来完成。
  <=> 比较两个对象的大小,大于、等于、小于分别返回1,0,-1
   === 右边的对象是否在左边区间之内,返回true, false
   =~ 匹配:用例比较是否符合一个正则表达式,返回模式在字符串中被匹配到的位置,否则返回nil
   !~ 不匹配:断言不符合一个正则表达式,返回true,false。
  <= < >>= 小于等于 小于 大于 大于等于
  == != 等于 不等于:比较两个对象的值是否相等,返回true, false
   eql? 比较两个对象的值、类型是否相等,返回true,false。
  equal? 比较两个对象的内存中地址是否相同,返回true,false
【8】条件判断语句:
  判断条件是否相等用“==”
  Ruby里,nil和false为假,其他都为真。
【9】循环语句
  For .. in , while, until
   迭代器:times, upto, downto, each,step
【10】异常与线程:
  Ruby中用begin/end…rescue…ensure…raise来处理异常rescue必须在ensure前。


7.             Watir 语法快览:

【1】文本框<INPUT id=”email” name=”_fmu.u._0.e”value=””/>

   方法1:ie.text_field(:id,’email’).set(“文本内容”)

   方法2:ie.text_field(:name,‘email’).set(“文本内容”)

   方法3:ie.text_field(:name,“email”).clear

【2】下拉框

  <SELECT name=”cert_no”>

   <OPTION value=”身份证”>身份证</OPTION>

   </SELECT>

   方法1:ie.select_list(:name,”cert_no”).select(“身份证”)

   方法2:ie.select_list(:name,”cert_no”).clearSelection

【3】超链接<a href = http://www.google.cn/>google</a>

   方法1:ie.link(:text,”google”).click

   方法2:ie.link(:url,http://www.google.cn/).click

【4】复选框<input type = “checkbox” name = “checkme”value = “1”>

   方法1:ie.checkbox(:name,”checkme”).set

   方法2:ie.checkbox(:name,”checkme”).clear

   方法3:values =ie.checkbox(:name,”checkme”).value

   多个同名复选框的处理:

  <input type = “checkbox” name = “checkme” value =“2”>

   方法1:ie.checkbox(:name,”checkme”,”2”).set

   方法2:ie.checkbox(:name,”checkme”,”2”).clear

【5】单选框<input type = “radio” name = “clickme” id= “1”>

   方法1:ie.radio(:name,”clickme”).set

   方法2:ie.radio(:name,”clickme”).clear

【6】一般按钮<input type = “button” name = “clickme”value = “Click Me”>

   方法1:ie.button(:value, “ClickMe”).click

   方法2:ie.button(:name,”clickme”).click

【7】submit按钮

  <form action = “submit” name = “submitform” method =“post”>

   <input type = “submit” value =“Submit”></input>

   </form>

   方法:ie.button(:value,”Submit”).click

【8】图片按钮

  <form action =”submit” name = “doitform” method =“post”>

   <input type = “image” src = “images/doit.gif” name =“doit”>

   </form>

   方法:ie.button(:name,”doit”).click

【9】Form中无按钮

  <form action = “login” name = “loginform” method =“get:>

   <input name = “username” type=”text”></input>

   </form>

   方法1:ie.form(:name,”loginform”).submit

   方法2:ie.form(:action,”login”).submit

【10】获取隐含对象值<INPUT type=hiddenvalue=”您的Email”name=”field1”>

   方法:values =ie.hidden(:name,’field1’).value

【11】获取窗口对象

  方法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/) #正则表达式匹配获取

【12】URL编码

  requ