1.1自动化测试从零开始
1.1.1 引言
>>自动化测试就是以程序测试程序,以代码代替思维,以脚本的运行代替手工测试
>>自动化测试能做到什么?
回归测试
运行更多更繁琐的测试
执行手工做不到的测试,如压力测试,和长时间的测试
具有一致性和重复性
具有可复用性
多环境下测试
>>自动化的缺点
不能完全代替手工测试
无法完全保证测试的正确性
手工测试发现的缺陷远比自动化测试多
要版本基本稳定后才能进行
成本过发高风险的
对测试技术有一定的要求
>>什么时候适合引入自动化测试
系统周期长,系统版本不断
需求变更不频繁
系统中的测试对象基本可以正常识别
系统中不存在大批量的第三方控件
需要反复的测试
>>什么时候不适合引入自动化测试
项目周期短,需求变更频繁
软件版本还没有稳定的情况下
没有明确的测试计划
领导不支持
多数对象不支持,脚本维护频繁,自动化测试注定失败
1.1.2严格的自动化测试流程
>>合理的自动化测试切入点
大部分公司以系统测试完成作为自动化测试的切入点
>>测试自动化分析
可行性分析:常见的有项目时间紧,需求变换无常,项目周期短,测试工具是否匹配项目
>>抽样demo分析
可以抽取其中的部分模块做自动化测试,一般选择冒烟测试
>>测试需求分析
即自动化测试想要完成的任务,比如分析哪些功能需要做成自动化测试,一般选择正向的(符合我们需求的)
>>测试计划的指定
计划越全面,后期实施越规范
>>自动化测试设计阶段
包括框架的设计:好处脚本模块化,数据驱动,日志分析,共享对象库,公共函数,环境配置,异常处理,场景恢复等等
自动化测试用例设计:和手工测试用例差不多,自动化测试用例可以参考手工测试用例,包括如下的几个步骤:1.筛选手工测试用例(一部分可以直接使用,一部分要转换)2、转换手工测试用例3、增补测试用例
>>测试脚本设计与开发
脚本分为:线性脚本,结构化脚本,可共享脚本,数据驱动脚本,关键字驱动脚本
编写自动化测试脚本的参考
自动化测试脚本代码必须严谨规范
测试用例是开发的参照物
开发过程多利用插桩和断点
开发完毕后至少运行三次以上才可认为脚本没有问题
>>自动化测试执行
1、无人值守的测试
环境搭建
测试用例和测试脚本绑定
测试用例排列与组合
2、异常处理和场景恢复
3、一个自动化测试执行实例(QC)
用例上传到QC和QC进行绑定
>>提交自动化测试产物
执行结果,分析报表,和测试报告,质量情况等
>>测试脚本维护
时时刻刻贯穿在测试流程里边
1.1.3 自动化测试用例详解释
>>原则一:覆盖核心业务流程,或重复执行率较高的流程
>>原则二:以正向为主
主要还是用于回归测试,就是有了新的功能,老的功能不能影响
>>原则三:并非所有的手工测试用例都能自动化
>>原则四:自动化测试需要回归点
脚本完成复原:举例:修改密码,修改完了需要把密码还原,否则下次无法运行
初始化数据:举例,发送消息,首先要把所有的消息删除,再发送消息
>>原则五:自动化测试需要回归点
不需要每一步都写测试结果,可有可无的检查不需要做。
1.2帮助文档
如何获取最新的帮助文档
http://h20230.www2.hp.com/selfsolve/manuals
>>F1的妙用
焦点切换
脚本定位跟踪:双击定位对象和方法
>>查询example
双击关键字,按下F1,看不懂查看example
1. 3录制与回放
1.3.1拒绝录制
如果靠录制+加强是不能设计出好的脚本,只有直接编码才能根据设计思想完成脚本
线性脚本属于录制的范畴
缺点:1、比如录制过程中采用了active功能,脚本将变得非常大
2、录制时候QTP对对象自动命名,需要自己手动去改,效率不如一个的添加对象
1.3.2录制功能适合新人学习
录制相关知识点:
1.3.2.1 Add-in Manager&BHO Manager
Qtp启动页面让选择的就是插件,其中web插件式常常使用到的,如果需要其他的插件需要向官方购买,或者自己定制
什么是插件?
目的就是让QTP能够识别对象,web网页是于使用的语言没有多大的关系,只有桌面程序与使用到的语言才有关系,针对C++,java,C#,QTP都有自己的插件提供
实例:百度按钮
首先使用spy识别百度按钮,发现识别成了webbutton
启动QTP时取消web插件,只选择visualbasic插件,再次识别发现根本就识别不了此对象(按钮上没有黑边框),只能把整个浏览器识别成了一个对象
还有一种情况,就是即使我们使用了web插件,有时候也会出现无法识别对象的情况,是因为我们先打开IE在再打开QTP的,QTP在IE中识别对象是依靠BHO Manager
Class动态链接库识别对象,必须在打开QTP后,再打开IE才会自动加载BHO Manager
,否则无法正确识别对象。注意一下:BHO依托于浏览器,浏览器存在它便存在
1.3.3.2 Record and run settings
第一个选项:避免同时打开两个网页,有可能会报错,所以我们在测试程序执行最好把一些不相关的网页把它都关掉,可以利用程序来关掉不相关的网页。
第二个选项:录制和回放的时候打开指定的网页
第二个个选项适合初学者,一般使用第一个选项,使用systemutil这个函数
Windows application的是类似的,不累述
1.3.3.3 Web event recording configuration
分为三个等级:
Basic
Medium
High
用户还可以自定义,还可以恢复默认设置
例子:鼠标悬停在前程无忧的logo上,发现basic的level无法录制,但是把level提高到高等级的时候,就可以录制了。脚本如下
Browser("招聘,找工作求职,上前程无忧").Page("招聘,找工作求职,上前程无忧").Link("温州").FireEvent "onmouseover" |
FireEvent 函数比较常用
1.3.3.4录制脚本的注意事项
开始录制前关闭不必要的浏览器
如果弹出安全警告,选择启用禁用这些对话框,或把安全警告加进对象库
要对web对象进行录制,要对web对象值进行更改和还原
录制脚本基本没有问题,如果自己写代码遇到了问题,可以参照录制
实例:录制百度WebRadioGroup控件
Browser("招聘,找工作求职,上前程无忧").Page("搜索设置").WebRadioGroup("SL").Select "1" Browser("招聘,找工作求职,上前程无忧").Page("搜索设置").WebRadioGroup("SL").Select "2" Browser("招聘,找工作求职,上前程无忧").Page("搜索设置").WebRadioGroup("SL").Select "0" '还可以这样写 With Browser("招聘,找工作求职,上前程无忧").Page("搜索设置") WebRadioGroup("SL").Select "#1" WebRadioGroup("SL").Select "#2" WebRadioGroup("SL").Select "#0" End With |
1.3.3 录制时需要注意模式的切换
模式有:
正常的模式,通过识别对象
模拟录制模式:模拟鼠标光标拖动的操作,例子:画图
低级录制模式:除了录制键盘和鼠标,还录制了坐标,一旦对象的位置改变,回放就会失败。不到万不得以不要采取此操作。
一般使用正常模式,在对象实在无法识别的时候考虑使用其他两种模式。模拟录制和低级录制一般要比正常录制浪费更多的磁盘空间。
1.3.4 QTP回放机制
回放就是根据脚本顺序执行,那么QTP是如何找到对象的?
1、 根据脚本中的对象名到对象库中获取相应的对象。
2、 根据对象库的属性找到页面的对象的对象。
比较重要的几个设置
1.3.4.1 File-Settings-Run
1) Datatable iterations
2) When error occurs during run session
3) Object synchronization time out:同步延长时间,默认20秒
4) disable smart identification during run seeeions:屏蔽智能识别功能
5) save image of destop when error occurs:错误时截图,保存在report里边。
注意此功能仅限于业务组件脚本的运行
注意要和QC脚本连通,否则报错
1.3.4.2 File-settings-Web
Browser navigation time out:页面最大加载时间,在网络等原因,导致页面加载过慢,待超过规定时间后,脚本就进行下一个步骤,导致找不到对象
1.3.4.3 Tools-options-run
1) run mode:两种模式,一种是 fast,一种是normal
这个选项是每个步骤之间的停顿时间
Fast是没有停顿的,如果以QC调用qtp脚本,默认使用fast模式。
1.4远离QTP脚本录制模式
QTP的视图有专家视图和关键字视图,推荐使用专家视图
Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("注册").Click Browser("百度帐号注册").Page("百度帐号注册").WebEdit("email").Set "zhouhui_aaaa@126.com" Browser("百度帐号注册").Page("百度帐号注册").WebEdit("loginpass").SetSecure "11" Browser("百度帐号注册").Page("百度帐号注册").WebEdit("verifypass").SetSecure "11" Browser("百度帐号注册").Page("百度帐号注册").WebButton("注册").Click |
Browser("百度帐号注册").Page("百度帐号注册").object(" ..").
大多数就是如上的格式当然也有例外,比如
Browser("百度帐号注册").frame(“..”).object("").
使用专家视图的好处:
QTP使用脚本语言vbscript,可以在专家视图里边自如编写代码,还有QTP使用的对象库编程和描述性编程只能在专家视图中进行,而这些在关键字视图中是无法进行的。
1.5对象库(上)基础篇
1.5.1 引言
到了这一章接触到了脚本,这一章比较重要,想要精通对象库编程这个开发模式,我们必须精通对象库。
对象库分上下两篇,上篇介绍对象库的机制和原理,下篇介绍对象库的编程。
不精通QTP对象库,一定不是一名合格的自动化测试工程师
1.5.2 对象库的出现改写了软件测试历史
一旦读者精通了QTP,会觉得各项功能都和对象库产生了必然的联系
1.5.3 对象库原理,机制,及操作流程
1.5.3.1对象库模型老大,object identification
1)封装实际对象,转化为QTP对象到对象库
2)运行时对比对象库里的对象属性和被测对象的实际属性
3)对比一致,匹配成功,不一致报错提示无法识别对象
也就是,对象库模型就是QTP把各种对象都分门别类起来,建立了一个对象模型,webbutton代表的是按钮,webedit代表的是文本框等。QTP加对象到对象库之后,会自动建立被添加对象的对象模型。每个对象有有一个可以唯一代表某对象的属性列表,这个属性列表是可以维护的,页面就是identification
如何觉得默认的属性不够,或者多余,可以自己手工进行设置。
举例:
Remove webedit的type属性
然后把百度的文本框加入到对象库
发现:该对象的属性列表也也变成了两个,原来没移除之前是三个的。
QTP在运行的时候发现有一个与mandatory properties不一致的时候就会报错。而且设置object identification的时候要保证要唯一能确定这个对象。
智能识别介绍
只能识别就是,如果使用正常的识别方式识别不了对象的话,就会启用智能识别功能,首先会智能识别基本属性,找不到对象才会启用备用属性,按次序一个一个的筛选,直到识别到对象为止。
1.5.3.2以一个简单的实例揭开QTP的篇章
1)打开百度首页,添加搜索框对象到对象库
2)在专家视图中编写代码,要求,设置值为“QTP”
3)回放脚本
代码如下:
browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "QTP" |
1.5.4 对象库基本操作
1、 test object 故名思意,就是存放测试对象
2、 checkpoint and ouptputobject 检查点和输出对象,用处不大
3、 action 切换,添加对象的时候注意action一定要选对
4、 对象的剪切与复制删除等,对于剪切复制或者删除父对象那么子对象也被前剪切,复制或者删除。
5、 望远镜:查找功能还可以替换
6、 Add object to local添加对象:注意添加对象的时候,所选择对象的所有父对象也被添加,而子对象不被添加。属于同一个页面的对象,添加后会自动隶属到那个页面下。因为添加对象必须先切换到要添加对象的页面才能成功选到对象,在不同的页面上添加对象会有点繁琐,这个时候用到了QTP的捕捉模式切换,这边先不讲。
小实验:证明手工添加对象远比录制添加对象来的快捷
录制的缺点是:对象命名由QTP自动命名,有时候不知道所命名的对象究竟代表了什么,而且录制的时候把不需要的对象也添加进来了。
录制产生的代码:
Browser("百度帐号注册").Page("百度帐号注册").WebEdit("email").Set "1" Browser("百度帐号注册").Page("百度帐号注册").WebEdit("loginpass").SetSecure "50238cc5e5e5a7ab" Browser("百度帐号注册").Page("百度帐号注册").WebEdit("verifypass").SetSecure "50238cc67ed10d22" Browser("百度帐号注册").Page("百度帐号注册").WebEdit("verifycode").Set "1" Browser("百度帐号注册").Page("百度帐号注册").WebCheckBox("isagree").Set "OFF" Browser("百度帐号注册").Page("百度帐号注册").WebButton("注册").Click |
添加对象后手写代码:
browser("注册").Page("注册").WebEdit("邮箱").Set "1" browser("注册").Page("注册").WebEdit("密码").Set "1" browser("注册").Page("注册").WebEdit("确认密码").Set "1" browser("注册").Page("注册").WebEdit("验证码").Set "1" browser("注册").Page("注册").WebCheckBox("是否接受").Set "ON" browser("注册").Page("注册").WebButton("注册").Click |
可以看到手写的代码更加简洁明了,为什么说省时呢,因为QTP自己命名的对象太长或不直观需要自己手动在对象库里边修改,预期时候修改,还不如在添加的时候修改,这样不容易忘记对象。
7、 对象的更新
版本更行后原先的对象作了变化,这个时候就要更新,有时候即使对象没有变化,也做需要做更新操作,不知道为什么(作者的经验)
8、 对象闪烁
是个非常常用的按钮,如果对象更新之后,点击这个按钮,对象不高亮显示,说明识别不了对象,这个时候要对对象库属性做修改。
补充:每个对象都有一个隐藏的方法:highlight
browser("注册").Page("注册").WebEdit("邮箱").highlight |
9、 Object spy 后面重点会讲解
10、 Associate repositories
实例:
题目:要求Action1点击视屏
Action2在编辑框输入文字,点击百度一下按钮,点击视屏
Action1中不添加任何对象,action2中只添加百度一下按钮对象
有两个可用对象库文件一个是link.tsr,一个是edit .trs分别存放视屏和百度编辑框对象。
Action1 如何引用link.tsr,只需要把link.tsr加到action1即可
注意,左侧的avaiale action只代表当前脚本的action,右侧代表需要把指定对象库加到哪个action中
动态加载QTP对象库
RepositoriesCollection.add "D:\cora\软件外包学院培训\QTP培训\脚本\第一章\reporsitory\link.tsr" |
但是脚本运行结束之后就不存在了。
如下是使用vbscript 后台语言调用对象库:
Function addObjectRepository( objectRepositoryName) If instr(objectRepositoryName,".tsr")<>0 Then rePath=objectRepositoryName else rePath=objectRepositoryName&".tsr" End If RepositoriesCollection.RemoveAll() RepositoriesCollection.Add(rePath) pos=RepositoriesCollection.Find(rePath) msgbox pos If pos<>1 Then msgbox "找不到副对象" End If End Function
Call addObjectRepository( "D:\cora\软件外包学院培训\QTP培训\脚本\第一章\reporsitory\link.tsr") |
11、 对象库中对象类型的分类和切换
筛选出各类对象,包括关联对象。
知识点扩展:如何将副对象转正?
把对象模式切换到all objects
然后在对象上面右击,选择copy to Local
注:父对象向一旦copy,那么父对象的父对象等等都被copy。
其他知识点的补充:
如图:export local object和export and replace local object
第一个故名思意,第二个,就是到处,并且取消本地对象以副对象来替代,所保存的文件就是副对象文件。
1.5.5 Object spy
1.5.5.1结交侦探
就是一个对象探测器,用于识别对象的属性
有三种方式:1)菜单 2)工具栏 3)object repository
显示对象的区域:默认停格在被测试对象上,如果想查看父对象,只要点击即可
Native properties和identification properties
本地属性,就是实际对象有多少属性(对象控件自身接口的属性),identification properties
QTP默认为对象封装的属性。本地属性比identification properties多的多。
注意一下:为什么QTP把百度搜索框识别成一个webedit,依据就是 identification里边的Class Name
Identification properties 涉及到对象库编程中的 TO 和RO,TO和RO编码的时候就是用的identification属性
对于前者:native properties有其独特的调用方法。
文字显示区域:比较好用,在编程的时候经常会用到,可以复制
请注意使用F1!,operations显示对象的方法,可以通过F1查找。
1.5.5.2 捕获对象时的模式切换
普通模式下没办法选择如百度模糊匹配
半操作模式-ctrl键,再放开(支持鼠标操作)
全操作模式-ctrl+alt,分别放开 ctrl和alt进入全操作模式,选中对象后,按住ctrl键再放开(支持鼠标加键盘)
1.5.6 对象库的最高指挥官(object manager)
可以用来管理对象,如对象的合并等等,大多数选项和object repository一样,不同的是:
Enable edit:对象打开的时候默认是置灰的状态,这个选项就是击活对象。
两个的工具:tools-object repository comparison
用来比较两个对象库有没有冲突的地方
另外一个工具tools-object repository merge toos
一个好的公共对象库,会提高测试的效率。
注意:管理对象库就像管理你的程序,必须有统一的命名规则和标准。
作业:
1、生成两个或多个本地对象库,然后把他们合并。
1.6 对象库(下)进阶篇
1.6.1 引言
1.6.2 基于expert view的对象库编程必备知识
1.6.2.1手写代码的三种方式
第一种:步骤生成器,insert->step generator(F7)
Category 下拉框有三种类型(test objects,utility objects,还有functions)
实例1:test objects
点击OK后在专家视图中就可以生成一行代码了。
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Click |
注意:这里可以对参数进行参数化。
第二种:complete word方式
1)右键单击语言栏目,点击设置
2)点击键设置
3)更改按键顺序
4)选择下一个选项
因为QTP默认的快捷键是ctrl + space,而我们的中英切换又是使用的ctrl+space,所以只能改变中英切换的方式。
小例子:如图所示(使用ctrl+space键)
注意一下:对象也在complete word里边呢!(基于对象库的编程)
总结:complete word是是目前写QTP代码过程中使用效率最高的一种方式。可以大大提高QTP的工作效率。
第三种方式:对象拖动的方式
把对象从available keywords视图中拖到专家视图中即可轻松搞定。只需稍微改改就好了
强力推荐这种方式,效率最高。
1.6.2.2其他知识点
1、垂直选取法,鼠标左击左上角,向右拖动一定的距离,右击鼠标进行选取,这样一次可以对多行进行选取,并且可以输入替代的关键字,如dim
2、代码换行,用于一行太长,分行显示
Browser("百度一下,你就知道")._ Page("百度一下,你就知道")._ WebEdit("wd").Set "cora" |
3、 Alt+G 定位函数(不适合外部函数)
方法:选择function名,按住alt+G即跳到指定的function块。
4、ctrl+shif+space(参数提示,用于某些情况下参数消失了)
4、 基于类和函数的complete word(alt+.)
Ctrl+space 不适合类
注意:此方式只适合于QTP9.2之前的版本
5、 with end with
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Click Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "cora" ' 可以写成 With Browser("百度一下,你就知道").Page("百度一下,你就知道") .WebButton("百度一下").Click .WebEdit("wd").Set "cora" End With |
1.6.3 封装对象模型-test objects VS Run-time objects
1.6.3.1什么是TO 什么是RO:
TO 即测试对象
RO 即runtime object,运行时对象
TO是为了运行时能识别对象而存在的
1.6.3.2 GETRO,GETTO,SETTO
属性很重要:1是可以验证检查点,二是获取有用的价值属性来做后续的事情
1)例子:获得对象库属性
加入代码
valueTo=Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("新闻").GetTOProperty("text") msgbox valueTo |
2)getTopProperties
set allProperties=Browser("百度一下,你就知道").Page("百度一下,你就知道").Image("百度首页logol").GetTOProperties msgbox "有 "&allProperties.count&"个属性" For i=0 to allProperties.count-1 properyName=allProperties(i).name properyValue=allProperties(i).value print properyName&"="&properyValue next Set allProperties=nothing |
getTopProperties 一般较少用到
3)SetTopProperty
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").SetTOProperty "name","百度一万下" msgbox"中断脚本" |
注意:1、运行上述代码的时候在msgbox这一行要加上断点,因为它只会在运行时改变对象库中的值。断点是ctrl+F9
取消断点是 shift+ctrl+F9
2、SetTOProperty "name","百度一万下"不能加括号,因为它是没有返回值的(即调用sub不要用括号)
企业项目案例:
假设页面上有无数个item,每个item后面都有一个check按钮,此时要一个个加到对象库里边是不可能的,假设页面上有一个edit控件,用来获取item的数目,此时的代码可以这样写:
ButtonNum=cInt(javawindow(“text”).javaEdit(“recordnum”).GetROProperity(“value”)) For buttonIndex =0 to ButtonNum-1 javawindow(“text”).javaButton(“check”).SetToProperty(“index”,buttonIndex) javawindow(“text”).javaButton(“check”).Click next |
另外一个案例:没怎么看懂?
4)GetRopProperty
获取运行时间的对象属性。
拿百度搜索框来说,注意一个问题:我们不能在add properties的时候把value属性加入到description properties里边,因为description properties是运行时必须和runtime object属性完全匹配,因为value添加的时候是空的,而运行时是输入值的,所以导致不匹配会报错。
这个应用太广泛了,几乎所有的验证点都需要用到此属性。
总结:
我们可以使用spy来识别对象属性,在识别web对象的时候,我们可以使用微软的IDEDevToolBar和sqy配合一起使用,来轻松识别对象属性。
1.6.3.3 对象封装属性的真正源头
所有对象的封装属性都在这:
1、 在运行对象框中输入 regedit
2、 选择 HEKY_Current_User->software->Mercury InteractiveàQuickTest Professional->micTest->attribute
还记得之前说过spy 识别时的Class Name不是QTP的封装属性呢,因为,在注册表中没有这个关键字,只有micClass
另外还有几个隐藏属性,在spy中不显示的,常用的隐藏属性有:source_index,index,creationtime等
例:
index=Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").GetROProperty("source_index") Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("source_index:="&index).set "QTP" |
注意一下:每个属性都有对应的对象,如creationtime只能用在browser对象上面。
1.6.4 梳理运行时的对象的封装与自身接口的属性区别
1.6.4.1解读对象的自身接口
上节主要讲的是对象的封装接口,本节主要讲对象的自身接口,这两种接口的区别是:
1、 封装接口是对象的不完全属性,有些对象的属性是封装接口无法获取到的。
2、 运行时对象(RO)可以看见自身接口的所有属性,而对象库中测试对象只可以看见被的封装的一些接口。
3、 封装属性是不能修改实际运行时的对象,只能获取属性的值,而自身接口就可以。
利用对象自身接口,修改实际运行时的对象属性
with Browser("百度一下,你就知道").Page("51Testing软件测试网-中国软件测试人的精神家园") .Image("51Testing软件测试网").Object.src="http://www.baidu.com/img/baidu_sylogo1.gif" .Link("注册").Object.innerText="加入百度(注册)" end with |
当然这只是一个假象,刷新一下就恢复原样了
再来复习一下
对象.object.自身属性
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Object.innerText="百度一万下" |
对象.object.自身方法
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Object.click |
获取运行时的属性
editvalue=Browser("百度一下,你就知道").Page("百度一下,你就知道")._ WebEdit("wd").Object.value : msgbox editvalue |
注意,如果把不同的语句放在一行要以:号隔开。
例:为文本框赋值
'利用封装属性 Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "QTP" '利用对象自身的属性 Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Object.value="this is QTP" |
总结:注意1:对象的自身接口不能对象库中的属性
同一个对象的自身属性和封装属性有时是不一样的如innerText,innertext
几种常见的对象无法识别或识别错误的原因
1、 软件程序的对象无法被QTP识别
大多数对象都无法识别,这种项目是最好不要使用QTP做自动化测试
非得做的话有如下的几种解决方案
1) 设置虚拟对象
不推荐
2)使用相对坐标然后配合WSH去定位对象
Wsh方法在后面会讲到
3) 使用DOM组件和接口,只适合web项目
4) 使用QTP自定义扩展SDK Customer来进行二次开发,使QTP能够识别对象
(是QTP最高深的技术,请联系本书作者,作者的联系方式在本书的最后边)
5) 开发专属插件
此时的测试主力已经不是QTP了
6) 把无法识别的对象放到dll里边由QTP来调用
此方法使用的是extern对象
2、 对象可以被QTP识别,但是加载的插件不正确
3、 同一个界面出现两个或两个以上相同属性的对象
这种情况,为每个对象做一个唯一的标识符,最常见的就是index
4、 实际运行时的对象发生了改变,导致对象库不匹配
这个时候只需要动态的或的运行时的值,动态的放到对象库中就可以了。
1.7描述性编程
省略,详见csdn
1.7.3 Object Identification与spy的妙用
在描述性编程的时候,如果不知道选择什么样的属性做描述的话,我们可以使用Object Identification查看,使用spy查看属性的值。
1.7.4 描述性编程的妙用和对象库编程的混搭
1)如百度首页有很多的link,一各个加到对象库里边由点麻烦,此时可以使用描述性编程
Set baidu=browser("micClass:=Browser").page("micClass:=Page") print baidu.link("name:=新闻").Exist With baidu print .link("name:=图片").Exist print .link("name:=知道").Exist print .link("name:=关于百度").Exist End With |
2)如果同时打开多个相同的浏览器窗口
systemutil.Run "C:\Program Files\Internet Explorer\iexplore.exe" systemutil.Run "C:\Program Files\Internet Explorer\iexplore.exe" browser("CreationTime:=0").Navigate "http://www.51testing.com/html/index.html" browser("CreationTime:=1").Navigate "http://www.sina.com" |
CreationTime等于-1的时候说明有且只有一个窗口
If browser("CreationTime:=-1").Then msgbox "当前只有一个浏览器窗口" else msgbox "有0个或多个浏览器窗口" End If |
3)使用描述性编程遍历n个同类型的属性
Set editObject=description.Create editObject("micClass").value="WebEdit" Set alleditObjects=browser("title:=.*").page("title:=.*").ChildObjects(editObject) For i=0 to alleditObjects.count-1 Set oEdit=alleditObjects.item(i) oEdit.set "12" Next Set oEdit=nothing Set alleditObjects=nothing Set editObject=nothing |
4)对于一些控件动态产生,比如,根据输入的数量,会动态产生对应数量的文本框,并且他们都有一定的命名规则,如name1,name2,name3…
此时如果使用对象库不是现实的,比如我输入数量100,是否就要向数据库中加入100条数据呢?
For i=0 to 100 Browser("title:=.*").Page("title:=.*").WebEdit("name:=name"&i).set "firstname" Next |
1.7.5 对象库编程vs描述性编程
描述性编程胜
1.8数据池
1.8.2.3 global sheet VS local sheet
Global sheet 是全局变量受此页面控制的
Local sheet 是局部变量,不受datatable iterations的控制,不过可以这样控制,选择被调用的action,在keyword view上选择
从这里可以看出,global sheet相当于执行了三次脚本
Action sheet相当于自行了三次自身action的迭代
1.8.2.4 test datatable VS Run-time datatable
test datatable:事先准备好的数据
Run-time datatable:执行过程中向datatable里边填的数据
实例:
(1)进入百度首页
(2)在搜索框中输入QTP字样
(3)点击百度一下按钮
(4)校验在搜索结果的页面中的搜索框是否保留了原来的QTP字样
如下是其中的一种验证方式,还有一种验证方式,那就是EOM(在这里不做讨论)
systemutil.Run "http://www.baidu.com/" Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "QTP" runTimeData=Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").GetROProperty("value") datatable.Value("PG",1)=runTimeData Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Click
runTimeData=datatable("PG",1) actualData=Browser("百度一下,你就知道").Page("百度搜索_qtp").WebEdit("wd").GetROProperty("value") If runTimeData=actualData Then msgbox"验证通过" else msgbox "验证不通过" End If |
大家注意一下:运行时的数据表在结果文件中查看
总结:为了分享各个不同的action的公共数据,此时要用global sheet
1.8.4 用好datatable使脚本更加灵活
Datatable是QTP的一个保留对象,下面列举常用的方法
1 动态的向datatable中添加新列,并且赋值
datatable.GlobalSheet.AddParameter "PG2","hello" |
2、动态的向datatble中增加新行,并且赋值
datatable.GetSheet("Action1").SetCurrentRow(2) datatable.Value(1,"Action1")="RowValue" |
4、 动态的获取datatable中所指定的值
gValue=datatable("PG","Global") msgbox gValue gValue=datatable(1,"Global") '引申出另外一个应用 For i=0 to N msgbox datatable(i,"Global") Next ‘如何保证在action1和action2获取数据的时候保持行数一致 datatable.GetSheet("Action1").SetCurrentRow(2) datatable.GetSheet("Action2").SetCurrentRow(2)
currentRow=datatable.GetSheet("Action1").GetCurrentRow datatable.GetSheet("Action2").SetCurrentRow(currentRow) |
5、 动态的获取datatable中,所指定行的值
getValueByRow=datatable.GetSheet("Action2").GetParameter(1).ValueByRow(2) msgbox getValueByRow |
6、 获取到datatable总行数的命令
allCount=datatable.GetSheet("Action1").GetRowCount msgbox allCount |
1.9 Actions
1.9.1使用action来控制好业务流
注意QTP10.0之后,使用了 test Flow View
总结:action的三个概念
1、 非重用型:只能被存储它的test调用
2、 重用型:可以被存储它的test调用,也可以被外部脚本调用
3、 外部型:一个存储在别的test中的reusable action,此action只能在调用它的脚本中是只读的。
1.9.2 call action的三种方式
1.9.3 action的切分
鼠标定位在脚本的第二行
点击 split action后
脚本被成功分成两半
1.10验证点和测试报告
1.10.3 抛弃工具自带的检查点使用QTP验证点函数
QTP自带的验证点函数 object.CheckProperty属性名,属性值,等待时间,结果在result文件中体现。
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "QTP" Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").CheckProperty "value","QTP" |
1.10.4 灵活自定义验证点
使用CheckProperty有点生硬,由此引出了一个比较灵活的函数
For i=1 to 4 If i=1 Then Reporter.ReportEvent micPass,"step1","micPass=0" elseIf i=2 then Reporter.ReportEvent micFail,"step2","micFail=1" elseIf i=3 then Reporter.ReportEvent micDone,"step3","micDone=2" elseIf i=4 then Reporter.ReportEvent micWarning,"step4","micWarning=3" End If Next |
1.10.5 走进QTP Report-test Report
这几个参数的优先级,即只要有一个步骤失败了,那么整个脚本都会被标记为失败
micFail - micWarning- micPass - micDone
有一个特别的设置:jump to step in QuickTest,跳到相应的脚本
1.10.6 自定义验证点-HTML模式
有一点点不懂(详见:tarun的第16章)
set oWebEdit=Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd") validateProperty oWebEdit,"name","wd" 'validateProperty oWebEdit,"name","wd1" Function validateProperty(object,PropertyName,ExpertedValue) If object.GetROProperty (PropertyName)=ExpertedValue Then HReport ExpertedValue,object.GetROProperty (PropertyName),true,_ "check"+object.GetTOProperty("testObjName")+"<"+PropertyName+">属性" validateProperty=True Exit function Else HReport ExpertedValue,object.GetROProperty (PropertyName),false,_ "check"+object.GetTopProperty("testObjName")+"<"+PropertyName+">属性" End If End Function
Function HReport(ExpertedValue,ActualValue,testStatus,nodeName) Set oEventDesc=CreateObject("Scripting.Dictionary") oEventDesc("status ")=micFail oEventDesc("EnableFilter")=false oEventDesc("NodeName")=nodeName oEventDesc("StepHtmlInfo")="<table border='1'>"&_ "<TR><TD>ActualValue</TD><TD>"+ActualValue+"</TD></TR>"&_ "<TR><TD>ExpectedValue</TD><TD>"+ExpectedValue+"</TD></TR>"&_ "<TR><TD>Check Status</TD><TD style=''background-color:red><b>failed</b></TD></TR>"&_ "</table>" If testStatus Then oEventDesc("status ")=micPass oEventDesc("StepHtmlInfo")=replace(oEventDesc("StepHtmlInfo"),"<TD style=''background-color:red><b>failed</b></TD>","<TD style=''background-color:green><b>passed</b></TD>") End If newEventContext=reporter.logevent("replay",oEventDesc,reporter.GetContext) Set oEventDesc=nothing End Function |