QTP主要采用的是使用GUI模拟人的操作。它在模拟人的操作时会记录操作的对象及所做的操作和顺序,然后在回放时按记录顺序操作这些对象。而在这个模拟的过程中,最重要的莫过于界面对象(控件)的识别,那QTP是怎么做的呢?下面就举一个小例子来说明:
比如我们要测试内网论坛http://XXX.XXX.XXX/bbs/index.php用正确的用户名和密码是否能成功登录。登录界面如下:
QTP自动化测试原理
测试步骤大概如下:
1. 要先识别用户名输入框、密码输入框、登录按钮控件
2. 在用户名输入框中输入正确的用户名
3. 在密码输入框中输入正确的密码
4. 点击登录按钮
5. 验证是否登录成功,要验证是否成功登录,那就得知道成功登录与失败登录的区别。成功登录后的页面如下:
QTP自动化测试原理
我们可以通过验证红色框中的内容或验证绿色框中的内容来标识登录是否成功,然后记入测试报告。
以上只是一个小例子,从中可以看出识别对象是一个很重要的问题也是一个很困难的问题,毕竟现在的控件类型越来越多(包括第三方插件或自己开发或定义的控件)。那QTP是怎么来识别对象的呢,下面通过讲解QTP识别以上小例子中的控件的方法来说明一下:
首先,QTP是通过记录控件的属性来标识对象的(当然具体用哪一些属性,QTP是有默认的,也可以配置)。假设QTP使用“html
tag”和“name”属性来识别对象,QTP是怎么处理的呢?请先看下图:
QTP自动化测试原理
图-QTP对象识别
在使用QTP录制时,QTP会把对象存储到对象库中。而对象是按如上图的方式存储于对象库中。即,QTP会默认给录制的对象取一个名字(这个名字可以自己改,只要在脚本中使用到此对象时保持和此名字一样就可以了),然后把识别此对象的属性和属性值存储到对象库中,我们可以先把识别对象的属性集合认为是一个属性包,接着就是把识别此对象的属性包与定义的对象名进行关联,也叫做对象映射。这样一个对象就存入对象库了。
接着来说明QTP是如何调用这个对象的。例如,在“用户名输入框”中输入“a用户”,伪代码如下:
WebEdit(“用户名输入框”).Set “a用户”
现在分析一下这个语句:
首先,QTP会通过“用户名输入框”这个名字到对象库的对象名中查找,会找到以下这个对象名:
QTP自动化测试原理
然后通过找到的对象名,找到对象名映射的属性包,如下图:
QTP自动化测试原理
接着QTP就会通过这个属性包来匹配页面上的控件的属性,如果在页面上找到一个唯一与此属性包匹配的控件,那QTP就会认为此控件为要找的控件。
然后QTP根据“WebEdit”来确定控件的类型,并调用QTP对于此类控件内置的操作方法“Set”把“a用户”赋予了控件
至于其他控件的识别和操作,基本原理和上面一样。检验登录是否成功,也是通过比对登录成功后的页面特有的控件的属性值来判断。
QTP还提供描述性编程,从而可以不使用对象库,如在“用户名输入框”中输入“a用户”,可以使用以下伪代码:
WebEdit(“Html tag:=INPUT”,” Name=username”).Set “a用户”
细心的朋友可能已经发现,上面只是把识别对象的属性包中的属性和属性值按一定规则直接写到了“WebEdit()”的括号内了。这时QTP将不通过对象库,而是直接使用括号内的属性和属性值到页面上去找匹配项。然后操作与使用对象库的操作一样。
当然,QTP还提供了一些其他的功能,比如参数化,划分模块(Action)等。但最重要的还是对象的识别。
个人认为QTP的脚本运行其实就是一组对象有组织的执行自己的方法,最终完成一个流程的过程。当打开一个web时,想要脚本能够模拟人来操作整个流程,那多就要求这个脚本能够识别人的每一个操作,而人的操作实际上是对web页面上控件的操作,所以只要QTP的脚本能够识别人操作过的控件就可以模拟人的操作流程,而web页面上的控件都是QTP脚本中的对象,也就是说只有QTP脚本中的对象能够被唯一的识别出来,就可以模拟人的整个操作流程。而QTP又是如何识别对象的呢?
对象识别原理就是获取hwnd,然后判断ui属性,逐个判断,然后逐层递归,最后获取每个对象的所有层面的属性,跟对象库里的属性进行比较,匹配则应用。也就是说在你添加一个对象到对象仓库中的时候,该对象的主要属性都被保存到对象库中了,回放QTP脚本的时候实际上就是在被测试软件中寻找指定的对象,然后按照这些对象指定的方法去完成一个动作,而这些方法就是把windows
win32中、web上的一些activex控件中的方法和微软控件对外的接口中的一些方法进行封装,成为qtp自己的方法。对于任何一个add-in都是先找到人家的对外接口,然后拿过来封装,需要的时候去调用接口事件,也就成为了QTP的动作。
所以QTP脚本回放实际上就是要做两个步骤:1)识别出要操作的对象控件。2)识别出对象控件后来完成该对象控件指定的方法。
在QTP识别对象的时候是按照对象的唯一属性来区分的,有时候QTP对象仓库保存的对象属性是不完全的,导致两个很相似的对象不能够识别出来,这样脚本就会报错,或者说对象仓库中对象的属性每次都是变化的,那么每次回放脚本也会和对象仓库中保存的不一致导致脚本报错。这里介绍一个很好用的web对象的属性——object属性。
QTP为用户提供了两种操作对象的接口,一种就是对象的封装接口,另一种是对象的自身接口。
对象的自身接口是对象控件本身的接口,只要做过软件开发,使用过控件的人应该很清楚。
对象的封装接口是QTP为对象封装的另一层接口,它是QTP通过调用对象的自身接口来实现的。
两种接口的脚本书写格式的差别在于:
自身接口需要在对象名后面加object再加属性名或方法名,
封装接口就不用在对象名后面加object。
比如操作JavaEdit对象,通过QTP封装的封装接口,脚本如下:
设置JavaEdit的内容:
JavaDialog("Add NE").JavaEdit("NE Name").Set
"NE1"
读取JavaEdit的内容:
msgbox JavaDialog("Add NE").JavaEdit("NE
Name").GetROProperty("value")
如果通过JavaEdit的自身接口,脚本如下:
设置JavaEdit的内容:
JavaDialog("Add NE").JavaEdit("NE Name").object.setText("NE1")
读取JavaEdit的内容:
Msgbox JavaDialog("Add NE").JavaEdit("NE
Name").object.getText()
QTP执行JavaEdit().Set语句时,是通过执行JavaEdit().object.setText()来实现的。
QTP执行JavaEdit().GetROProperty("value"),是通过执行JavaEdit().object.getText()来实现的。
JavaEdit对象的封装接口Set()和GetROProperty("value"),是QTP封装JavaEdit对象的自身接口setText()和getText()而得来的。
对象的封装接口是QTP使用的缺省接口,我们录制出来的脚本都是使用封装接口,大家用的也都是封装接口。
但是封装接口不如自身接口丰富,因为QTP只是封装了部分常用的自身接口嘛。
所以我们在需要时,可以绕过封装接口,直接调用对象的自身接口。
不过有些自身接口不够稳定,在实践中偶尔会出现问题,但是概率很少。
封装接口有相应功能的话,就尽量用封装接口吧!
理解了封装接口和自身接口的原理,我们就可以更加灵活的操作对象了。
但是我们怎么知道对象都有哪些封装接口和自身接口呢?
其实很简单,用对象查看器(Object Spy)查看对象,在查看窗口里有列出这些接口,包括属性和方法。
窗口中间有选择栏让你选择Run-time Object或者Test Object,
当你选择Run-time Object时,它显示的就是对象的自身接口(自身的属性和方法)
当你选择Test Object时,它显示的就是对象的封装接口(封装的属性和方法)
明白了这些,你还等什么呢?快拿起对象查看器,看看对象都有哪些封装接口和自身接口,肆意的操作它,玩弄它吧!
比如执行
JavaDialog("Add NE").JavaEdit("NE Name").object.setVisible(false)
哈哈,你的JavaEdit对象就当场消失不见了!!! |