SCMLife.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 9145|回复: 2

[推荐] 使用RFT 8.0 识别 SWT 应用程序中的 GUI 控件

[复制链接]
发表于 2011-6-19 23:45:51 | 显示全部楼层 |阅读模式
本帖最后由 技术狂人 于 2011-6-19 23:54 编辑 ( A1 ?, `3 e, H6 i8 p

$ q+ ]4 X' Y3 f( F; YRational Functional Tester 是 IBM Rational 研发的一款面向对象的自动化测试工具,可以模拟用户在实际使用中的基于图形化界面的操作。它支持 Windows 和 Linux 平台上对多种应用程序的测试,可以满足各种用户多方面的需要。
( {2 c/ x7 Y; L0 r" ?* `# n6 |9 c' B7 ^9 C/ z, K
SWT(Standard Widget Toolkit),是 Eclipse 平台上使用的标准窗口小部件工具箱,它能向开发者提供和本机平台一致的用户界面。除了标准的 Eclipse 平台,SWT 目前还广泛应用于 RCP(Rich Client Platform)。RCP 是由 Eclipse 平台进化而来的开放性开发平台,本质上是 Eclipse 的插件,当开发应用程序时,能够得到 Eclipse 的底层支持,利用 Eclipse 平台 UI 外观和框架来快速地进行开发。
% A3 p. }7 M* r! g. u5 b1 t# u4 F9 x( @, _5 {" h  q
Rational Functional Tester 8.0 强化了对 Eclipse 平台的支持,可以捕捉到完全使用 SWT 库开发的应用程序中的控件对象。但是,由于 SWT 的一些不足,Eclipse 组织基于 SWT 进行了扩展(如 Nebula、Draw2D 和 JFace),帮助其满足常见的用户界面编程需求。扩展后的图形库含有一些特殊控件,令 RFT 对其难以识别。另外,一些 SWT 控的属性中存在不确定的字段,这也给识别造成了困难。因此,本文将介绍如何使用 RFT 对 SWT 原生态控件进行识别,并针对难以识别的控件给出三种不同解决方法,以帮助用户生成高效的自动化脚本。; n* q# L5 M+ q6 S0 J
0 h3 h9 V' u' Z% z
测试 SWT 应用程序的环境准备
. a% x, V& v! Y) e% ?
2 K* T# R* @, K在测试 SWT 应用程序之前,需要对应用程序进行配置,使 RFT 能够对 SWT 控件进行识别。+ p3 A  d! m3 H# _
在 RFT7 及以前的低版本中,需要将下图中的代码添加到 SWT 应用程序的源代码中,其中:Bootstrap 类是 RFT 的运行时环境中 rational_ft_bootstrap.jar 文件包中的类。这种方法虽然可以是 SWT 控件被识别,却需要手动更改源代码,增加了不必要的负担和风险。
3 l! j; Y& ~' w% [# p1 Q* n' y" o- i" {. R: @  z
清单 1
% e+ x2 l4 ?+ }
try{    Bootstrap.enableSwtUi(display);}catch(Throwable throwable){            }

' [% K6 e. u4 S1 e7 O而 Rational Functional Tester 8.0 提供了更为方便的配置方法,通过插件的安装达到 SWT 控件识别的目的。首先要将其安装路径下的 EcliseEnabler 文件夹中的内容复制到应用程序的插件文件夹,对应用程序配置文件进行修改。之后启动 RFT,配置 Eclipse 平台并启用 GEF 支持(GEF 是一套 MVC Framework,View 的部分常常基于 SWT)。这样,测试 SWT 应用程序的环境就准备好了。具体步骤可以参考 Tech note
* E2 k  q2 G! ~: h% g

+ C# }: r2 \! U+ A3 u! B& V+ ^5 h* |. t! c8 d
用 Rational Functional Tester 8.0 识别 SWT 原生态控件
, U& ?, Z7 H  ^4 H, S. R! o" r( d在 RFT 中,对 SWT 原生态控件的识别是通过测试对象映射来实现的。当用户创建一个 Functional Test 脚本后,在脚本资源管理器视图中就会出现与这个脚本相关的测试资源。而这个脚本专用的测试对象映射就包含在测试对象文件夹下面,如下图所示。  X$ ]5 m; t7 n/ c% h
1 b; N; g7 D2 c: s
图 1. 脚本资源管理器视图
, W: |9 @  U; ~; R6 W: H4 l
3 ^) t% |& T- l, n" J除了脚本资源管理器,用户还可以从“脚本”菜单中打开测试对象映射。双击打开专用测试对象映射,在“测试对象”菜单中点击“插入对象”,得到如下图所示的对象查找器。5 i/ c' p/ I/ }( R
9 u3 M0 {' z6 q$ g, F
图 2. 对象查找器2 h0 G$ G; ?) ^/ ?
& f, {- e3 s. Y- s( X& X; {$ K
点击对象查找器旁的按钮,出现手型图标,拖住小手到需要识别的控件,如果此控件可以被 RFT 识别,会发现它被红色框线包围。松开鼠标,继续对选择对象的个数和范围进行具体定义。其中包含三个选项,分别是:仅选中的对象、包含所选中对象的兄弟对象、以及包含本窗口所有可用对象。三者涵盖范围递增,如何选择视用户需要而定。完成选择后,此控件就可以显示在测试对象映射中。如果此控件不能被 RFT 识别,那么当手型图标拖到它上面时,控件不会被红色框包围。
! s" `1 r& y3 L下图为一个用 SWT 开发的应用程序,其中按钮“Edit”为原生态控件。使用对象查找器,可以捕捉到它,并且在按钮旁边出现它的属性类别“org.eclipse.swt.widgets.Button”。松开鼠标,选择“仅选中的对象”,将此控件添加到测试对象映射中。
' ]1 s4 `4 r' ]9 I4 P# Y/ K1 D$ K- X5 u  d
图 3.RFT 识别 SWT 原生态控件" y) v7 Q( ~+ U- Q, o& b4 G1 t

; M6 ^2 Q) R4 o7 d' h4 x/ H如图 3,在测试对象映射中,按钮控件的属性被显示在“Recognition”标签下,除了属性名称,还包含此属性对应的值和它的权重。权重的数值越高,说明通过这个属性来识别控件的准确性越高。因此,在这个例子里,.class 和 text 的权重最高,可以通过下列代码在脚本中对控件进行识别,返回类型为 TestObject。# w) L5 e5 @: Y! m: G

% G: r! E# ]8 U. V$ X1 V3 P- Z7 K清单 23 G( S% _4 x7 s1 Y
RationalScriptTest.find(atDescendant(".class",                "org.eclipse.swt.widgets.Button", "text", "Edit"));

) x7 J- s3 w- d  [- Z4 g
( g" d( T. q: D9 C
" L% j+ h; O/ T6 d9 E+ p+ I4 R
运用 Rational Functional Tester 8.0 识别 SWT 特殊控件遇到的问题
5 f. w- ]) R5 F  f虽然 Rational Functional Tester 8.0 对 SWT 原生态控件的识别很有效。但在识别特殊控件还会存在困难。在本章中,将具体举例说明 RFT 在识别特殊控件过程中遇到的三类问题。
' ^8 s- g6 d( \* c! TEclipse Nebula 中的 Grid 控件4 ~7 p4 G# B8 n2 a  A
首先不容易被 RFT 识别的是在 SWT 基础上扩展的图形库 Nebula 中的 Gird 控件。前面提到过,Standard Widget Toolkit(SWT)通过 Java™技术提供对操作系统的原生窗口控件的访问,但可用的控件不能解决所有需求。因此,Eclipse Nebula 提供九个控件来帮助满足常见的用户界面(UI)编程需求,而 Grid 部件正是其中之一。它是一种表格式的组件,该组件很好的添加了标准 SWT Table 组件中的功能,经常在 SWT 应用程序中被调用。5 l/ V' c5 V. q5 i" m
下图 4 展示了 Grid 控件被 RFT 捕捉的情况,其中,红色框所包围的对象为 Grid 控件,对象查找器在红框的右下角显示出了对象的类型为:org.eclipse.nebula.widgets.grid.Grid。(如果拖动手型查找器,试图捕捉 Grid 中更小的范围,则不会出现红色框。这就可以初步判断,Grid 的行、列不能被捕捉。)% S& G! w" I7 E5 t, _8 X& T
$ G/ e; a: r  J8 @/ D  l1 U$ @
图 4. 插入对象3 W  L. \- c( A$ v% t: I9 ~7 z5 S. M
! x7 ~" k2 g2 i% }5 X
松开手型对象查找器,在“选择对象选项”对话框中选择“包含本窗口所有可用的对象”,点击完成按钮,得到的测试对象映射如图 2 所示。
2 k4 B2 s5 \# F* J* H( L6 w( t$ R: u8 r) W+ F2 E: R
图 5. 包含本窗口所有可用的对象* h1 ?% K/ r  b9 i

# x0 |( P! @3 l  I1 n0 W从测试对象映射中可以看出,Grid 的确是对象查找器能抓取到的最小对象,它下面不包含其它控件,对于 Grid 中的行、列,以及可编辑的单元格无法以对象的方式识别。也就是说,虽然 RFT 可以抓取整个 Grid,其中的数据却只能通过鼠标点击的坐标来定位,如果以坐标的方式对单元格进行操作,并录制成自动化脚本,那么回放脚本时,坐标稍有改变,单元格就变得无法编辑,其数据就无法被读取。因此,如何能避免以坐标来定位 Gird 单元格是自动化脚本开发人员要面对的一个难题。本文的第四章将针对这个难题给出解决方案。5 t9 n6 `! H) l
Grid 控件中的内嵌 SWT 控件
4 r5 [7 b9 o3 f8 F  D9 H在自动化脚本开发过程中,除了对 Grid 单元格进行读取和编辑操作,还有可能会出现一种更复杂的情况:在 Grid 控件的单元格内嵌入其它标准 SWT 控件,而该控件在单元格内通常状态下不被显示出来,只有鼠标激活单元格时才会显示,一旦鼠标焦点离开,控件又不可见。为了实现这种状态变化的控件,开发人员往往自行开发 Grid View 设计不同的 Action Listener“包”在 Grid 外层。如图 3 所示,为 Grid 单元格中嵌入下拉列表。
; H4 d2 m# A- D2 c7 c# e; q# x
3 \3 }% p9 E8 V7 L  {图 6. 含有内嵌 SWT 部件的 Grid
+ Z. S2 A  {, {! W2 ~) Z/ H/ F+ x
; Y* q: @0 ]6 A; h. E2 K% I在这种状况下,当鼠标激活单元格时,下拉菜单对象可以被 RFT 捕捉到。但当鼠标选中下拉菜单中具体项时,如果因为焦点移动触发了使下拉菜单变为不可见的 Action Listener,选项文本或索引则很难被捕捉到,也就无法用下面两种语句开发自动化脚本来实现下拉菜单中项目的选择。
. h/ H. Z' K& x# o& S
% w2 }0 H( }; I0 C9 I清单 3  }# c) w( z' b1 T$ K' \" O8 j( p
        combo().click(atText(String));        combo().click(atIndex(Int));
- E( b2 c+ E- a2 r. F
因此,如何操作 Grid 内嵌控件及其子项是自动化脚本开发人员要面对的另一个难题。本文的第五章将针对这个难题给出解决方案。1 T1 T6 K" \3 ]1 Q" m- R. u$ d
属性存在不确定字段的 SWT 控件, z) C8 y% k8 G
前面两个难题都是由 SWT 的扩展控件所产生的,但即使 SWT 的原生态控件,某些情况下也会令 RFT 无法识别。例如,SWT 控件的属性本身存在不确定的字段,而识别过程中又需要判定这些字段,这就会给识别造成了困难。如下图 4 所示,SWT 应用程序的版本号为 Dev Build 1.2.x.9。& k- ^  {. v4 Y" P$ L+ y2 F! A1 u
3 ~, V. x+ Y% j
图 7.SWT 应用程序中 caption 以及对象映射图
8 j1 \7 z- \4 X: E, n# { ; N$ Y. S; b* p9 G5 D( }
从测试对象映射中可以看到,应用程序的对象类型为 org.eclipse.swt.widgets.Shell,可进行对象识别的属性为 .capionText。如果以 Employee Tool Dev Build 1.2.x.9 赋值给 .captionText 来识别 Shell,那么当版本改变后,Shell 将无法被 RFT 捕捉到,脚本无法回放,如图 5 所示,版本号为 Dev Build 1.3.x.12。4 H: @+ t' _6 K( W0 Z8 d

" ~: h9 W% e" {图 8.SWT 应用程序中升级后的 caption 以及对象映射图
% O7 n, R! g/ h$ L4 N + n9 M% |8 ~; u- a# Z" p
除了版本号不稳定的这种情况,还有另外几种情况是由于 SWT 控件属性本身存在不稳定的字段,造成识别困难,在本文的第六章中,将针对这些问题一一列举,并给出解决方案。
$ a1 {) u8 S- ?3 H, w9 \  [
) G- R9 A. L9 Z" d, {: L

9 C( ~/ B. |5 B/ m% q利用“编码解析识别控件”的方法识别特殊控件
) n* J! C0 l# j  l3 a; ^6 @针对第三章中提到的 Grid 控件难以识别的问题,本章将具体介绍了如何利用“编码解析识别控件”的方法解决这个问题。+ g3 ^7 J% h, z8 i
获取 Grid 控件的可用方法8 e, u! ~2 l' \1 _! Q& k  ]
要对 Grid 控件进行解析操作,首先需要查看 Grid 控件可用的方法。RFT 的 TestObject 类为用户提供了 getMethod 方法,帮助用户在不清楚源代码的情况下得到控件本身的方法及方法的属性。为此,用户需要在用 RFT 中的手型对象查找器捕到 Grid 控件并将其添加到测试对象映射中后,通过右键菜单“添加到脚本”。如下图所示,gird 对象就被添加到“脚本资源管理器”的“测试对象”文件夹下面。' d0 Y4 H* U" Z; }
* N5 j& u( G) ^9 w' \9 i' L# I
图 9. 插入对象
* Y* W( N- ~! f- m% m3 f, \# H! H* H
& B  v0 C$ v( y将光标放在脚本中准备插入 grid 对象的位置,右键点击 gird 对象,在菜单中选中“在光标处插入”,这样,grid 对象就可以在脚本中调用其 getMethod 方法了,具体调用方法如下。
# S' j& G( p. v- G7 G# T( I4 d/ j/ Z. d2 _
清单 4
* a' U8 V5 M' W. u! A
MethodInfo[] m = grid().getMethods();for(int i=0;i< m.length;i++){ System.out.println("Method "+i+": name = "+m.getName();}
; G; v* f2 A5 U* K
运行这段代码,在控制台会打印出 grid 所有的方法,其中我们会用到的几个方法为:getItemCount、getColumnCount、getItems。其中,Item 指的 Grid 中的 row,而不是单元格。这些方法在后面的解析中都会用到。
: _$ s2 D5 h" O8 t4 Y解析 Grid 控件. h% a9 g1 z% t1 j; G4 p
获得了 Grid 控件的可用方法后,创建如清单 3 所示的 Grid 解析类 NebulaGridParser,这个类包含四个类变量,一个构造函数,和四个自动化测试中解析 Grid 时常会用到的函数,并需要传入一个 TestObject 作为参数。这个参数可以是图 6 中插入的 gird 对象。
2 g9 }) n8 [- R3 s: y7 M7 E- D7 B# M' Q; t- S/ H; l" S2 E8 N% c
清单 5. A/ Q, `3 |' E4 b0 P
import com.rational.test.ft.object.interfaces.TestObject; public class NebulaGridParser{     private TestObject[] rowList;  TestObject obj;  int itemCount = 0;  int columnCount = 0;   public NebulaGridParser(TestObject o){   obj = o;  itemCount = Integer.parseInt(obj.invoke("getItemCount").toString());  columnCount = Integer.parseInt(obj.invoke("getColumnCount").toString());  rowList = (TestObject[]) obj.invoke("getItems");  }   public int getGridRowCount(){  return itemCount;  }  public int getGridColumnCount(){  return columnCount;  }  public String getColumnHeader(int colIndex){  TestObject[] cols;  cols = (TestObject[]) obj.invoke("getColumns");  if (colIndex<cols.length){  return cols[colIndex].invoke("getText").toString();  }  return "";  }   public String getItemAt(int rowIndex, int colIndex){  String item = new String("asd");   TestObject objItem = rowList[rowIndex];  item =((TestObject)objItem).invoke("getText", "(I)Ljava/lang/String;",  new Object[]{new Integer(colIndex)}).toString();  return item;  } }
+ i5 {/ t! M6 v: X9 G" M
在类 NebulaGridParser 的构造函数中,首先将参数赋值给类变量 obj。之后,调用 invoke 函数返回 obj 的 item 数量,列数量,以及行数组。Invoke 方法类似于 java 中的反射机制,它可以根据字符串来调用相应的函数。此前通过 getMethods 方法查询到的三个方法 getItemCount、getColumnCount、getItems,在这里就是用 invoke 函数来调用的。用户可以通过如下语句判断函数返回类型。, x0 P# r2 z/ F* p& ^/ ^  B8 Z5 v

% J+ \9 `' |! ~) b清单 6
6 R+ O+ p( x: Z
System.out.println(obj.invoke("getItemCount ").getClass());System.out.println(obj.invoke("getColumnCount ").getClass());System.out.println(obj.invoke("getItems").getClass());
4 Z9 o- ~) [; L; c; x. a! t& v
从控制台的打印结果可以看出,getItemCount 和 getColumnCount 的返回类型为 Integer,表示行数和列数。getItems 方法返回的是 [Lcom.rational.test.ft.object.interfaces.TestObject 类型,即 TestObject 数组,表示行的数组。而 invoke 的返回类型是 Object,所以需要分别强行转换至 Integer 和 TestObject []。
( r# h- l- G  d解析函数 getGridRowCount 和 getGridColumnCount 分别为 NebulaGridParser 返回行数和列数。函数 GetColumnHeader 的作用是返回 Grid 的列名,即图 1 中的 Serial Number、Name、Gender、Job 和 Salary。函数 getItemAt 的作用是根据行号和列号定位 cell,返回单元格的内容。在这个函数里同样也用到了 invoke 语句用于 getText 函数的调用,所不同的是传递的参数。第二个参数“(I)Ljava/lang/String;”表示以 JNI 语法表示方法签名的字符串,第三个参数表示一组包含需要传递的实际参数值的对象。根据签名,这组对象应该为 Integer 类型。( [0 Y! e7 J9 L0 @/ D
NebulaGridParser 的四个函数可以帮助用户读取 Grid 的内容,但是如果需要对 Grid 进行编辑,比如向 Grid 输入数据,则需要在根据行号列号来确定鼠标需要点击的位置。为此,可以再添加一个函数 getPoint。
7 f6 C5 A, z, w5 [. `: U3 h! R  R% D4 D: L6 R- J4 h0 e, \
清单 7
2 J0 J/ m! Q1 A* @$ ?* R% F
import java.awt.Point;public Point getPoint(int rowIndex, int colIndex){            TestObject objItem = rowList[rowIndex];     java.awt.Rectangle re = (java.awt.Rectangle)objItem.invoke("getBounds",                         "(I)Lorg/eclipse/swt/graphics/Rectangle;",                         new Object[]{colIndex});             if ((re.height == 0 ) && (re.width == 0)){         return getPoint(rowIndex, colIndex);     }                return new Point(re.x + re.width/2, re.y + re.height/2); }

* U* X5 _, h3 U) ~) D1 f' U- ^7 CgetPoint 是递归函数,invoke getBounds 可以得到 Grid 中单元格矩形的边界,如果矩形的宽和高不同时为零,则返回宽,高减半,作为参数传递给 getPoint 函数,以此减小范围递归,最终返回鼠标需要点的位置。4 L( `; v/ N* u) Q3 r
调用解析函数2 h: A* X$ p* B. n+ [
NebulaGridParser 中的五个解析函数可以满足用户开发脚本时的一般需求,如果需要进行其它操作,则可以在它们的基础上进行新函数的创建。清单 5 显示了脚本中调用解析函数获取 Grid 中单元格内容的基本语句。) n5 W; Q  O5 A$ Q* T' W+ q! D$ J
: F/ j& j0 v5 X! s" ?
清单 8% G8 h- s+ }0 p. x
NebulaGridParser neb = new NebulaGridParser(gto);  cellContent = neb.getItemAt(row, column);
- y: B3 {/ B- m) B& ?' t7 }) Q
其中,gto 是 GuiTestObject 类型,可以将 Grid 对象赋值初始化。Grid 对象既可以是从应用程序中静态捕捉到的,也可以是 ITCL 框架下动态获取的 Grid。如果需要对单元格进行编辑,则可以在脚本中加入如下的基本语句。- H% K7 [! c; N# v4 T) g7 t5 n
; m0 T  J  w: y5 f5 Q9 f, y
清单 9, j" z3 C# ]; s2 K, j
NebulaGridParser neb = new NebulaGridParser(gto);  gto.doubleClick(neb.getPoint(row, column));  mainWindowAppObj.inputKeys(inputStr);
( j) p) Z+ v/ z
mainWindowAppObj 是被测试程序的 Shell 对象,其 inputKeys 方法在 Grid 中的单元格被双击后向其中输入数据。; A6 y1 _5 O% l, S, g  w3 ~


- i$ w. b7 i8 @* D3 F- O( \4 O, ~! O
) w1 X- R  l2 {2 J利用“热键识别控件”的方法识别特殊控件" A' U: s8 x# V; U* {
通过“编码解析识别控件”,Grid 控件已经可以被识别并操作,在本章中,将以下拉菜单(combo)为例,具体介绍如何以另外一种方式“热键识别控件”来解决内嵌控件识别困难的问题。但首先需要说明的是,通过上章介绍编码的方式也可以对其进行识别。: ^9 c0 P9 Z( Y3 N' z, }0 O" V
编码解析 Combo! |+ d% U! n, d1 P. }2 B" G+ _
在清单 9 中,首先的要对 Grid 控件进行解析操作,然后鼠标双击单元格激活显示 Combo,通过 find 方法获取此 Combo。之后,用 invoke 函数调用 setText,即可完成在下拉菜单中选择 United States 选项的操作。" r6 X8 q* y4 J# }

. W0 ?4 L- Y, N' }( S/ q# b清单 10
  y5 W2 F$ T. K4 b
     NebulaGridWidget neb = new NebulaGridWidget(gto);  gto.doubleClick(neb.getPoint(row, column));  TestObject[] to= gto.find(atDescendant(".class","org.eclipse.swt.widgets.Combo"));  If (to.length>0){ to[0].invoke("setText","(Ljava/lang/String;)V",  new Object[]{new String("United States")});      }

* U1 M) ^" f# C( h热键识别 Combo! L  `6 j4 {7 Z. K8 x5 \3 j5 M
既然可以通过上面的代码来识别 Combo,为什么还要选择通过热键识别 Combo 的方式呢?这主要是由于 Grid 中的列通常被部分折叠起来,列号与用户看到的并不相同,并且当条件改变时,绝对列号有可能改变。因此,与其每次当列号变化时由脚本开发人员手动更改代码,来确定列的绝对位置,不如通过热键识别列的相对位置。
$ l$ A( p! T* d  N& p3 m* h  i热键(HotKey)又叫快捷键,就是键盘上某几个特殊键组合起来完成一项特定任务。比如 Del+ctrl+alt 在 Windows® XP® 下可以打开 windows 任务管理器。使用热键帮助完成自动化脚本的开发可以提高其效率,但是,不同的应用程序对应的热键大多不相同。所以,脚本开发人员在使用热键帮助脚本开发之前一定要先确定待测应用程序所具有的各个热键组合的意义。
* E2 J' e3 Q7 @0 y  W; j在第二章中图 3 中的下拉菜单,位于 Country 列,相对于 Gender 是第三列,而它们的相对位置一般情况下不会改变。对于这个应用程序,Tab 键可以用于转向下一列。那么,在脚本中可以首先找到列 Gender,之后通过热键 Tab 找到列 Country,输入 United States 的首字符 U 定位到 Uganda,再用上下键找到 United States,最后由热键 Tab 或 Enter 使焦点离开,实现脚本如下图所示。, \  Q' z; a0 M# m

+ Z: b+ w/ J7 z( ?  l  H清单 11
' v4 A9 s: C! W2 P. B, X8 r! N
mainWindowAppObject.inputKeys ("{TAB}{TAB}");  mainWindowAppObject.inputKeys ("u{ExtDown}{ExtDown}{ExtDown}{ExtDown}{ENTER}");
$ Q2 d1 G& y+ t8 L4 b- |2 q% ~" e


7 S4 [6 L, p! D& _
0 h3 E" `5 g9 o/ F# g利用“正则表达式动态识别控件”识别特殊控件
( a; K: d/ m+ D7 o! g' z! B: w  Z正则表达式是一种由普通的字符及特殊字符组成的文字模式,用以描述在查找文字主体时待匹配的一个或多个字符串。虽然正则表达式是一个很庞杂的体系,但在自动化脚本中只要引用一些简单的语法,就可以在控件识别时起到事半功倍的效果。在这一章中就将介绍如何通过“正则表达式动态识别部件”的方法解决自动化测试中的难题。
8 x- `) b, j6 i利用正则表达式识别 Build Number
3 m/ b5 K: A5 x- G! U/ e- l在第三章中提到过如果 SWT 控件的属性本身存在不确定的字段,而识别过程中又需要判定这些字段,这就会给识别造成了困难。对于这种问题,正则表达式就可以提供很好的解决方案。以图 4 和图 5 中涉及到的 SWT 应用程序为例,无论是 Employee Tool Dev Build 1.2.x.9,还是 Employee Tool Dev Build 1.3.x.12,都含有相同的字段 Employee Tool Dev Build,只有后面的数字存在不确定性。而不论版本号如何更新,都符合控件查找需求。因此,可以将此类标题文本表示为正则表达式 Employee Tool.*。如果需要限定更小的需求范围,比如 Dev Build,那么正则表达式可以表示为 Employee Tool Dev Build.*。
: j6 J. i3 ?( @9 ^; F! ?5 F# U3 k3 f; E  ?* F: X* Z
清单 12
* h+ {+ V: p9 ~3 z$ b# K% K+ ?
public static GuiTestObject findMainWindow() {  RegularExpression windowCaption = new RegularExpression(  "Employee Tool.*", true);  TestObject[] shells = RationalTestScript.find(RationalTestScript  .atChild(".class", "org.eclipse.swt.widgets.Shell",  ".captionText", windowCaption));  if (shells.length == 1) {  return new GuiTestObject(shells[0]);  }  return null;  }

% R- z8 c- J8 a利用正则表达式识别 ToolBar
1 Z5 w1 ?2 f8 L6 V; W除了利用正则表达式来识别待测软件的版本号,在开发自动化脚本时还经常会遇到这种情况:ToolBar 作为一个载体包含很多的 ToolItem,如果对 ToolItem 定位,则首先需要对 ToolBar 进行定位。比如应用程序里的按钮 Save、Open 就常位于同一个 ToolBar,如果需要识别 Open 按钮,则需要先识别整个 ToolBar。而脚本开发人员并不关心这个 ToolBar 上具体包括除 Open 外还有哪些按钮,只要它含有所需要的 toolItem 即可。这时,就可以使用如下代码查找 toolBar。
) Y! J: A3 v5 V* H3 x  h& ~) o4 [' E
清单 13
: [+ {  p6 A5 m
public GuiTestObject getFileToolBar() {        TestObject[] toolbars = mainWindow.find(RationalTestScript                .atDescendant(".class", "org.eclipse.swt.widgets.ToolBar",                            ".itemToolTipText",                    new RegularExpression(".*Open.*",false)));         if (toolbars.length == 1) {             return new GuiTestObject(toolbars[0]);         }         return null; }
1 s5 x2 P& K0 Q8 V# k
清单 13 中,.*Open.* 表示含有 Open 的字符串,即通过 find 方法查找 .itemToolTipText 属性中含有 Open 的 ToolBar。待识别出 ToolBar 后,可以再通过 find 方法查找属性 .itemToolTipText 属性中含有 Open 字符串的 ToolItem,这样就可以找到按钮 Open。
2 ^& ?5 x" y# l. q利用正则表达式识别 Exception Dialog
8 f8 \5 Y* W" r  H自动化测试过程中如何捕获异常也是脚本开发时需要处理的问题。由于这些异常是不可预见的,且显示的文字内容存在着不确定性。因此,给异常对话框的识别增加了一定的困难。但是,无论什么类型的异常,在对话框中标签中往往包含 Error、Exception、Warning 等字段。所以通过正则表达式来识别异常对话框具有了可行性,实现代码如下。+ T/ c' n; K8 T4 k6 G

' ~  c$ R3 v3 E) i8 O9 ^7 D清单 14/ u3 `$ c+ }) m3 P
private static TopLevelTestObject findExceptionWindow() {  TestObject[] child = MainWindowObjects.getMainWindow().getOwnedObjects();   for (int i = 0 ; i<child.length; i++){  TestObject[] labels = null;  labels = child.find(RationalTestScript.atDescendant(  ".class", "org.eclipse.swt.widgets.Label",  "text",new RegularExpression (".*Error|Exception|Warning.*", true)  ));  if (labels.length == 1){  return new TopLevelTestObject(child);  }  }  return null;  }

' R. p: a1 x% O6 {( I( _' G) {在清单 14 中,find 方法中含有正则表达式 .*Error|Exception|Warning.*,表示异常框是含有 Error、Exception、Warning 三者中任意一个的字符串。利用此正则表达式,就可以对测试过程中捕获到的不可预见的异常。
# H  i' ?9 Y" k: t2 P+ R除了本章中涉及到的 Build Number、ToolBar 和 Exception Dialog,还有其它一些控件识别时也可以利用到正则表达式,在本文中就不一一列举了。读者可以在今后的自动化脚本开发过程中慢慢体会研究。" z" u4 A; w: F" i* z1 T

" v$ p2 X) X6 u7 O
0 F* F. L- @/ N& V
结束语6 H! o& U5 Y' n2 r
本文主要就 Rational Functional Tester 8.0 对 SWT 原生态控件和特殊控件的识别方法给予说明。其中,“编码解析识别控件”利用反射机制,令一些对象查找器找不到控件能够被脚本识别并调用,尤其是在 SWT 扩展图库不断增加的今天,“编码解析”的意义非常重要。“热键识别控件”虽然并不是必不可少的,但却简化了许多看似复杂的脚本开发过程,颇有些化腐朽为神奇的意味。“正则表达式识别控件”则减少了由于不确定性修改脚本的次数,增强了脚本的稳定性和可维护性。通过文章中所举的例子,用户可以对这三种识别控件的技巧有一个大致的了解。但是,怎样才能更好的应用于脚本开发的过程中则需要读者反复实践,认真体会。作者希望本文能够起到探路石的作用,帮助更多的脚本开发人员在自动化测试这条道路上走的更轻松。
# C" B! A. S/ z3 q6 j$ j
5 U) E4 s* b+ {0 o( R  k示例代码:NebulaGridParser.java   4 X5 m8 r( L/ J. x

  e- _0 ?: f7 b" P. M4 a. c

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
 楼主| 发表于 2011-6-19 23:49:07 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2013-7-5 15:50:01 | 显示全部楼层
谢谢共享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

SCMLife推荐上一条 /4 下一条

QQ|小黑屋|手机版|无图版|SCMLife.com ( 京ICP备06056490号-1 )

GMT+8, 2019-3-19 00:48 , Processed in 0.069620 second(s), 6 queries , Gzip On, MemCache On.

Powered by SCMLife X3.4 Licensed

© 2001-2017 JoyShare.

快速回复 返回顶部 返回列表