51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3455|回复: 9
打印 上一主题 下一主题

[原创] 【设计模式】 GUI层 -- 面向对象的扩展设计

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2009-11-30 10:16:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
分类:QTP自动化设计模式(原创)
作者:zzxxbb112   转载请注明

更多文章请见:http://blog.csdn.net/zzxxbb112
源码下载:http://download.csdn.net/source/1855793
摘要
本文主要介绍的是QTP的一种较为先进的技术,本技术是由AdvancedQTP SOLMAR自动化测试专家组所采纳的一种面向对象的设计模式,由Meir Bar-Tal于2008年12月20日发表,笔者将会详细介绍此设计模式的每个类以及方法,设计模式的使用,设计模式的优缺点。
此模式主要是把QTP描述性编程以及装载GUI对象的DICTIONARY对象通过业务驱动的方式来得到体现,最有价值的地方在于其对象识别的先发机制,可以有效的防止QTP在运行时识别对象出现卡住的现象,当对象出现不匹配时,能使测试顺利退出,并在报告中定位细节。有效的降低了测试的维护量并节省了自动化测试的时间。
介绍
自动化测试的核心问题就是如何减少维护量,例如:我们应该使用对象库还是描述性编程?如果选择OR那么我们可以在每个ACTION中使用共享对象库或者本地对象库,那如果选择DP,可以有什么方式来实现吗?
成本效益和可维护性是我们在做自动化测试中最为关注的,在此引出一个概念-GUI层扩展。这一概念经过的SOLMAR自动化专家组的分析和观察已被采纳,使用它就可以尽可能地提高代码重用性(通过使用面向对象的方法来提高效率,并分解出若干个抽象层且可维护性较高的自动化项目)。
层的概念
我们前面已经提到了GUI层,那层的作用是什么呢?这里先简单解释一下,层可以使重用化发挥到最大极限,定义一个类(封装一个图形用户界面层)通过相应的接口来控制应用程序GUI界面中的测试对象,从而把这个类称之为GUI层。
封装测试对象类
为了能够使大家更加容易理解此设计模式,我在这里重新修改了原文中层的方法和对象,这里就通过把百度搜索页封装成GUI层作为一个最简单的例子来讲解,代码如下:

首先看最外层的BaiduSearch类它代表着一个百度的GUI层,我们在类中定义了一个Scripting.Dictionary对象并且为其设置GET/LET方法,接着是一个初始化的函数Init这个函数主要的作用是把页面上下的所有对象全部封装在一个Scripting.Dictionary容器对象中,并通过描述性编程结合迭代式的对象封装有效的提高了代码的重用性,最后还有两个业务行为函数,一个是在文本框中输入搜索内容的行为,另一个是点击搜索按钮行为,这两个函数都是可以直接在字典对象中进行搜索关键字来定位对象的,并针对对象进行操作来达成关键字字典对象驱动。。这样一个百度的GUI层就已经封装好了,并且这个类还具备了两种业务行为的接口。
接下来来看另一个重要的函数,大家应该知道当QTP在运行时,测试对象一旦发生变化,与对象库中的对象无法匹配时QTP就会卡住直到超时,然后弹出错误框,在QC里执行也是一样,只是没有了错误框,这样的情况会导致在自动化测试中浪费很多无谓的时间,因此我们在GUI层中的INIT函数的最后加入了IsContextLoaded函数,此函数的作用就是在检查GUI层中所有对象的是否已经存在并且把结果进行返回。

由于QTP是不提供从外部文件中读取类的方法,因此我们在这里添加一个创建类的函数,接着我们的外部文件就已经封装好了,直接保存为*.vbs后就可以为QTP服务了。


调用业务行为
在QTP中加载之前保存的VBS文件后,在专家视图中输入以下脚本,就可以完成业务行为的调用了。

当脚本执行完毕后,会在结果报告中显示对象的存在与否,如果在运行时出现某个对象不能识别,或者说出现属性不匹配的情况,QTP就会立刻退出,并在结果报告中显示不匹配的那个对象来方便我们的定位,这其实也是本设计模式的一个比较明显的优势。
对象识别全部通过的结果图


个别对象识别未通过的结果图

通过上图我们可以看到当对象出现不匹配时,我们可以很容易的在结果报告中进行定位。

总结
优点:
  • 高效的重用化有效的减少了代码的维护量
  • 关键字字典驱动有效的提高了编码的效率
  • GUI层提供的行为函数接口使脚本与业务能够更好的关联起来
  • 对象检查的先发机制可以有效的防止QTP卡住的现象
  • 对不匹配的对象能够在结果报告中自动定位
缺点:
  • 由于QTP缺少类这一功能的提示,因此脚本编写没有了代码提示功能
  • 前期工作量较多,比较适合大型的自动化测试项目
  • 需要有一定的编码能力
参考文献:
《Implementing a GUI Layer with Classes》 December 20th, 2008 by Meir Bar-Tal


[ 本帖最后由 zzxxbb112 于 2009-12-4 13:12 编辑 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
发表于 2009-12-3 18:47:29 | 只看该作者
Great work!
回复 支持 反对

使用道具 举报

该用户从未签到

3#
发表于 2009-12-3 22:06:01 | 只看该作者
1,描述性编程在大型项目可用性非常低,不论是早期的代码量或者是后期的维护投入。
2,这样的代码量如果真的用到笔者“Meir Bar-Tal”所谓的大型项目,这样的代码量相当恐怖,无论是WEB,SAP,.NET,vb等等,一个页面的对象(涉及被操作的对象)都非常多,先不说使用描述编程,就搭建这个字典的工作量已经非常大。它只是为了确定某个环境某个对象的存在,是否值得大费周章。
3,这个设计模式是在跑某个用例前确定对象是否存在等,它存在的另一个问题在于某些对象只有在某个操作后出现,而针对这样的情况,还会需要代码再界定操作前与操作后。简单一个像下拉日期控件。

个人看法,一个不脱离对象库,像Meir Bar-Tal说的主要适用还是在Watir或者Pam30之类;一个不用字典,干脆直接遍历对象库。
而遍历对象库,包括了通用对象库与Current Action 对象库
Dim qtApp,Repository1,Repository2
Set qtApp = CreateObject("QuickTest.Application")
ActionName=Environment("ActionName")
Set Repository1=qtApp.Test.Actions(ActionName).ObjectRepositories
Set Repository2 = CreateObject("Mercury.ObjectRepositoryUtil")
Repository2.Load Environment("TestDir")&"\"&Environment("ActionName")&"\ObjectRepository.bdb"

接着传进需要查询的对象,并使用GetObject,GetAllObjects等方法获取对象
拼装对象,判断对象存在。
回复 支持 反对

使用道具 举报

该用户从未签到

4#
 楼主| 发表于 2009-12-3 23:02:05 | 只看该作者
ls说的没错,不过此文章只是SOLMAR发表的框架中的一小部分思维模式,在他们的框架中可以弥补LS说的问题~关键学习的是思想。
回复 支持 反对

使用道具 举报

该用户从未签到

5#
发表于 2009-12-3 23:49:41 | 只看该作者
是的。以后不用QTP,使用其它的脚本语言,这个是一个非常好的方法与思想。
回复 支持 反对

使用道具 举报

该用户从未签到

6#
 楼主| 发表于 2009-12-4 12:19:57 | 只看该作者
http://tech.sina.com.cn/s/2009-12-03/16483647277.shtml
51转载,至少也注明下吧~也是对作者的尊重~~很无奈。。。
回复 支持 反对

使用道具 举报

该用户从未签到

7#
发表于 2009-12-4 18:01:58 | 只看该作者
我做了实验果然可以,很强大,但是
我有个问题就是 我故意在添加“Submit”的后面把"Search"改成"Search1"
这样的话,测试的时候脚本跑到这里的时候还是弹出个Run Error 窗口后 死在那里了
回复 支持 反对

使用道具 举报

该用户从未签到

8#
发表于 2009-12-5 09:56:35 | 只看该作者
很好,已经为我所用了
特此通报一声
感 。。。。。感。。。。。谢。谢了。。。阿
回复 支持 反对

使用道具 举报

该用户从未签到

9#
发表于 2009-12-5 10:04:22 | 只看该作者
对了,光顾感谢了
还有个建议就是字典用后要释放阿,要不一直占的内存的尼

d = new ActiveXObject("Scripting.Dictionary");
d.Add ("a", "Athens");         // 添加一些主键和条目。
d.Add ("b", "Belgrade");
d.Add ("c", "Cairo");
...
d.RemoveAll( );       // 清除 dictionary。
回复 支持 反对

使用道具 举报

该用户从未签到

10#
发表于 2009-12-6 11:07:16 | 只看该作者
从作者的代码可以看到C++的痕迹
我试验了一下,思想确实很值得借鉴和学习,但在项目中的适用性还需要论证,至少我们的项目不适合。

还有个问题,可以改良
对象
a.b
a.c
a.d
如果a没有找到,就不要再去查找a.b和a.c了

胡说的,错了不要介意
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-25 22:17 , Processed in 0.067487 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

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