RFT 描述性编程.docx

上传人:b****6 文档编号:5363378 上传时间:2022-12-15 格式:DOCX 页数:17 大小:254.43KB
下载 相关 举报
RFT 描述性编程.docx_第1页
第1页 / 共17页
RFT 描述性编程.docx_第2页
第2页 / 共17页
RFT 描述性编程.docx_第3页
第3页 / 共17页
RFT 描述性编程.docx_第4页
第4页 / 共17页
RFT 描述性编程.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

RFT 描述性编程.docx

《RFT 描述性编程.docx》由会员分享,可在线阅读,更多相关《RFT 描述性编程.docx(17页珍藏版)》请在冰豆网上搜索。

RFT 描述性编程.docx

RFT描述性编程

RFT描述性编程

1问题与背景

在RFT中,识别web对象的方式有两种,静态识别-通过对象库的方式,动态方式-通过RFT的find方法或者通过child逐级查找方式来识别。

在动态识别时,存在这样三个问题:

1.识别速度慢,可能需要4-5秒才能完成一个对象的识别。

2.对编写不规范的html对象,很难识别。

对于没有id,name属性的对象,很难准确识别。

3.脚本编写复杂,不易读。

WLink.findHtmlLinkFromTextProp("登录",browser).click()

WTextFieldusernameText=newWTextField("username",".name","Html.INPUT.text",browser);

usernameText.setText("abc");

特别是在识别文本框时,需要通过查看html代码的方式来查看该对象的id,name属性。

在识别一些编写不规范的html对象的时候,如图片等,如果没有id,name属性,将很难准确识别。

可以通过增加以下3个特性,来解决这些问题:

Ø缓存节点路径,提高识别速度。

Ø根据页面信息来描述对象,增加识别手段。

Ø描述性编程,使脚本更易读。

2描述性编程

在RFT中,识别web对象的方式有两种,静态识别-通过对象库的方式,动态方式-通过RFT的find方法或者自定义的查找方式来识别。

在IBM的框架中,如要查找一个输入框,其属性.name的值为username:

WBrowserbrowser=newWBrowser(BrowserOps.findBrowser());

WTextFieldusernameText=newWTextField("username",".name","Html.INPUT.text",browser);

usernameText.setText("123");

首先获取到浏览器对象,然后在浏览器中不断的递归查找节点,当其节点的属性符合.name的值为username,.class的值为Html.INPUT.text时,即可返回。

在QuickTest中,可以通过描述性编程的方式来动态识别一个Web对象:

Browser().Page().WebEdit("name:

=username").set"123"

相比之下,QTP的这种描述对象的方式,将属性名称与值作为同一个字符串输入,并且可以输入多个属性名称与值作为参数,使用起来更加方便。

在RFT中,也可以使用同样的描述性编程的方式来识别一个对象:

Browserbrowser=newBrowser();

browser.getWebEdit(".name:

=username",".class:

=Html.INPUT.text").setText("123");

或者

browser.getWebEdit(".name:

=username").setText("123");

实现的步骤为:

2.1定位浏览器对象

RFT有一个特性,新打开的最后一个浏览器,通过getDomains()查找时,一定是最先找到的。

通过getDomains()获得Html进程后,通过getTopObjects()方法,就可以获得浏览器对象。

publicstaticTopLevelTestObjectgetLastBrowser(StringtoType){

RationalTestScript.sleep(0.5);

DomainTestObjectdomains[]=RationalTestScript.getDomains();

StringdomainName;

TestObject[]topObjects;

Hashtableht;

StringsClass;

booleanvisible=false;

for(inti=0;i

try{

domainName=domains[i].getName().toString();

if(domainName.equalsIgnoreCase("Html")){

topObjects=domains[i].getTopObjects();

if(topObjects!

=null){

for(intj=0;j

ht=topObjects[j].getProperties();

sClass=ht.get(".class").toString();

if(toType.equalsIgnoreCase(sClass)&&sClass.equalsIgnoreCase("Html.Dialog")){

if(ht!

=null){

visible=(boolean)ht.get(".visible");

if(visible){

return(TopLevelTestObject)topObjects[j];

}

}

}elseif(toType.equalsIgnoreCase(sClass)&&sClass.equalsIgnoreCase("Html.HtmlBrowser")){

return(BrowserTestObject)topObjects[j];

}

}

}

}

}catch(Exceptione){

//logger.error("Exception:

",e);

//noop-continueiftargethassincedisappeared

}

}

logger.error("foundnovalid:

"+toType);

returnnull;

}

如果查找不到浏览器对象,可以检查:

1浏览器是否打开。

2浏览器的add-on中,RFT的插件是否正确加载。

3如果安装的是jre1.7,win764位操作系统下,可能会出现不能识别浏览器的情况,可以尝试卸载jre1.7。

4win7下,通过runasadministrator来运行RFT,否则可能会出现脚本不能正确执行的情况。

2.2封装Web对象

下图是RFT的web对象继承关系图。

通过动态查找的方式来识别web对象时,都是从browser对象开始定位的,即BrowerTestObject.

为了便于操作,将页面上的对象封装成基类WebElement,所有的页面对象都继承自WebElement,实际就是对应于GuiTestObject.

类名

名称

主要识别属性

典型操作

典型对象

WebElement

所有的页面对象

.class

.id,.name

click

Html.DIV,Html.TR,Html.LI

WebButton

按钮

.class

.id,.value

click

Html.INPUT.button

Html.BUTTON

WebEdit

输入框

.class

.id,.name

setText

click

getText

Html.INPUT.text

Html.INPUT.password

Html.TEXTAREA

WebImage

图片

.class

.id,.name,.title,.src

click

Html.INPUT.image

Html.IMG

WebLink

链接

.class

.id,.text

click

Html.A

WebCheckBox

复选框

.class

.id,.name

check

uncheck

isChecked

Html.INPUT.check

WebRadioButton

单选按钮

.class

.id,.name

select

isSelected

Html.INPUT.radio

WebList

下拉框

多选框

.class

.id,.name

select

Html.SELECT

WebTable

表格

.class

.id,.name

getRowCount

getColumnCount

getCell

...

Html.TABLE

WinButton

弹出框按钮

.class

.text

click

Html.DialogButton

WinStatic

弹出框文本信息

.class

(index)

getText

Html.DialogStatic

publicclassWebElement{

GuiTestObjectwebElement=null;

publicWebElement(TestObjectto){

if(to==null){

webElement=null;

}else{

if(toinstanceofGuiTestObject){

webElement=(GuiTestObject)to;

}else{

logger.error("TestObjectclassisnotGuiTestObject:

"+to.getObjectClassName());

webElement=null;

}

}

}

}

publicclassWebEditextendsWebElement{

publicWebEdit(TestObjectto){

super(to);

}

publicvoidsetText(Strings){

this.click();//activatetextfield

this.clearText();

this.inputChars(s);

webElement.unregister();

}

}

2.3根据描述属性查找对象

识别一个Web对象,可能需要使用1个或者多个属性。

查找对象时,通过getChildren()方法来逐层查找,匹配这些属性,当属性值完全符合时,则认为已经找到。

1动态个数的输入参数,可以使用String...args来解决。

描述属性的key和value值通过:

=来分割。

如:

browser.getWebEdit(".class:

=Html.INPUT.text",".name:

=username").setText("123")

2将默认的.class属性写入,减少手工输入代码的工作量

publicWebEditgetWebEdit(String...properties){

HashMapdescMap=WebUtil.getDescMap(properties);

if(descMap!

=null){

if(!

descMap.containsKey(".class")){

descMap.put(".class","Html.INPUT.text");

}

}

WebElementtestObj=getWebElement(descMap);

if(testObj==null){

returnnewWebEdit(null);

}

logger.debug("foundtheobj");

return(WebEdit)testObj;

}

2先将字符串数组properties解析出属性的键值对,存放到HashMap中

`/**

*将".class:

=Html.A",".text:

=链接"的字符串描述转换成HashMap

*@paramproperties

*@return

*/

publicstaticHashMapgetDescMap(String[]properties){

HashMapdescMap=newHashMap();

String[]tempAttrbute;

for(Stringproperty:

properties){

tempAttrbute=property.split(":

=");

if(tempAttrbute.length==2){

descMap.put(tempAttrbute[0],tempAttrbute[1]);

}else{

logger.error("Error:

descriptionstringisinvalid:

"

+property);

returnnull;

}

}

returndescMap;

}

3按照属性在页面上查找对象

查找对象的方法,使用递归查找child的方法,其好处是,可靠性较好,只要页面上存在指定的对象,则必定可以查找到。

缺点就是查找速度慢,无论是按照深度优先,还是按照广度优先查找,因为必须将前序节点的属性都逐一进行检查。

不过这个问题可以通过后续的缓存路径的方式来解决。

publicstaticTestObjectgetChildObjects(HashMapdescMap,TestObjectparent){

TestobjecttestObj=null;

if(isMatchObject(parent,descMap)){

returnparent;

TestObject[]childObjs=parent.getChildren();

//循环查找直接子对象

for(inti=0;i

testObj=getChildObjects(descMap,childObjs[i);

}

returntestObj;

}

4属性匹配。

优先匹配.class属性

publicstaticbooleanisMatchObject(TestObjecttestObj,HashMapdescMap){

StringactualClass=null;

StringexpectVal;

StringactualVal;

HashtableproTable=testObj.getProperties();

if(descMap.containsKey(".class")){//优先匹配.class属性

actualClass=proTable.get(".class").toString();

if(!

actualClass.equalsIgnoreCase(descMap.get(".class"))){

returnfalse;

}

}

booleanisMatch=true;

for(Stringproperty:

descMap.keySet()){

if(!

property.equalsIgnoreCase(".class")){//逐个遍历剩下的属性

expectVal=descMap.get(property).trim();

if(proTable.containsKey(property)){

actualVal=proTable.get(property).toString().trim();

isMatch=expectVal.equalsIgnoreCase(actualVal);

}else{

isMatch=false;

}

if(!

isMatch){

break;

}

}

}

returnisMatch;

}

5增加index的识别属性。

通过描述的属性,可能会查找到多个符合属性的元素,可以增加index的属性,默认查找第一个,如果指定了index的值,则按照index的值返回对应的元素。

3缓存节点路径

通过深度优先或广度优先的顺序来查找页面节点,速度必然会慢。

为了加快速度,可以将第一次查找到节点的路径保存起来,第二次查找时,则根据之前保存的路径直接比对,以此提高二次查找的效率。

对每一层的节点按照顺序进行编号,每一层的起始编号均为0。

如上图,username的输入框的路径为0-1-0-0-0,密码的输入框的路径为0-1-0-0-1。

节点路径会保存在缓存文件(key-value的txt文件)中,key和value之间用两个#号分割,key为Web对象的描述属性按照指定顺序连接起来的字符串,value为节点的数字路径。

.class:

=Html.INPUT.text,.name:

=userId##0_3_0_1_0_4_3_0_0_0_0_0_3_0

.class:

=Html.INPUT.password,.id:

=oldPassword##0_3_0_1_0_4_3_0_0_0_1_0_3_0

由于同一个缓存文件中,并不能区分web对象所在的页面,所以,如果两个不同的页面上,都存在同样属性的web对象,如"确定"按钮,就会出现互相覆盖,导致缓存错误的情况。

另外在有些业务系统中,每个用户的权限不同,或者业务流程不同,同一个对象在同一个页面上的路径也会不同,如菜单,每个用户登录后的菜单顺序都会不同。

因此就需要采取以下措施来避免:

1将这两个对象保存到两个不同的缓存文件中。

2增加额外的描述属性来区别这两个对象。

如增加descName,extName这两个属性,它们不参与对象的属性匹配,但是会保存成不同的key值,形成两条不同的记录。

查找对象时的逻辑为:

1根据对象描述属性,生成唯一的缓存key值

2检查缓存文件,缓存文件中是否存在该key值。

2.1如果存在该key值,取出value--节点的路径

2.1.1在页面上,直接根据路径,找到对应的节点

2.1.2检查找到的节点是否符合描述的属性,

2.1.2.1如果符合描述的属性,则返回该对象。

2.1.2.2如果不符合描述的属性,根据缓存路径查找对象失败,跳转到根据属性查找对象流程

2.2如果不存在该key值,则根据缓存路径查找对象失败,跳转到根据属性查找流程

3根据描述属性,逐级在页面上查找该对象

4如果查找到符合属性的对象,将该节点的路径保存到缓存文件中,然后返回该对象进行后续操作

5如果未查找到符合属性的对象,提示错误。

通过缓存来查找web对象,大约0.5秒就能查找到正确的对象,足够满足自动化测试的需要。

publicstaticWebElementgetChildByCachePath(TestObjecttestObj,HashMapdescMap,StringcachePath){

if(cachePath!

=null&&cachePath.length()>0){

String[]cacheStep=cachePath.split("_");

intseq=0;

for(inti=1;i

seq=Integer.parseInt(cacheStep[i]);

TestObject[]tos=testObj.getChildren();

if(tos.length>seq){

testObj=tos[seq];

}else{

logger.warn("notfoundobjectbycachepath:

level="+i+"childcnt="+tos.length+",butexpectsequence="+seq);

returnnull;

}

}

logger.debug("foundone");

try{

if(isMatchObject(testObj,descMap,cachePath)){

returnsubTypeWebElement(testObj);

}else{

logger.warn("foundobjectbycachepath,butnotmatch:

"+descMap.toString()+"\t"+cachePath);

returnnull;

}

}catch(Exceptione){

logger.error("foundobjectbycachepath,butexcption");

logger.error("Exception:

",e);

returnnull;

}

}

logger.debug("nocachepathfor:

"+descMap.toString());

returnnull;

4根据页面信息来描述对象

一个普通的文本输入框:

  username:

|___________|

 这个文本框的html结构可能有这样几种形式:

  

   uesername:

/td>

   

  

或者

  

username:

现有的识别方式,都要通过查看这个输入框的id,name属性来识别。

对于这样一个输入框,人肉眼是如何来识别这个输入框的呢?

必定是根据输入框前的文本信息"username",而不是该输入框的id,name属性。

4.1通过左边文字来描述对象

那么在程序中如何来通过左边的文字来识别一个文本框呢?

  browser.getWebEdit(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1