精通QTP——自动化测试技术领航

978-7-115-26983-6
作者: 余杰 赵旭斌
译者:
编辑: 张涛

图书目录:

详情

本书的三大功能(一本合三为一的全能读物):教科书、实战项目指导书及测试管理人员参考书。 本书追求完美,在写作中也会有很多贴心的附加功能,如GPS导航、小技巧总汇等多项增值功能本书采用的是QTP现今最高版本10.0

图书摘要

精通QTP——自动化测试技术领航
51Testing 软件测试网 组编

余杰 赵旭斌 编著

人民邮电出版社

北京

《51Testing软件测试网作品系列》编辑委员会名单

编委:

王 威(具备多年软件开发经验和软件测试工作经验,对产品测试的方法和管理流程有深刻的认识, 51Testing软件测试培训高级讲师)

王 琰(具有丰富的通信终端产品的测试以及管理工作经验,51Testing 软件测试培训高级讲师)

朴春龙(Mercury认证CPC,自动化测试专家,51Testing软件测试培训高级讲师)

邓 强(具有丰富的软件系统测试工作经验,对功能性测试,自动化测试,性能测试及测试框架均有深入的研究,51Testing软件测试培训高级讲师)

陈 霁(ISO 内审员,积累了丰富的测试和管理工作经验,51Testing 软件测试培训高级讲师)

周 峰(信息产业部认证系统分析员,51Testing 软件测试培训高级讲师)

周春江(具备多年通信协议和通信终端设备的测试工作经验,51Testing软件测试培训高级讲师)

徐林林(熟悉大型应用软件的开发和测试流程;熟悉性能测试流程、方法和工具(如LoadRunner等), 51Testing软件测试培训高级讲师)

商 莉(多年从事软件开发、软件测试及质量保证方面的管理工作,51Testing软件测试培训高级讲师)

宋 锋(多年软件开发和软件测试工作经验,具备丰富的项目实战经验,51Testing 软件测试培训高级讲师)

宋光照(具有深厚的开源软件测试实践经验,擅长嵌入式测试,51Testing软件测试培训高级讲师)

刘德宝(多年软件测试及培训经验,参与门户网站、移动 BOSS 等多个大型软件测试项目,在自动化测试技术方面具有丰富项目经验,51Testing软件测试培训高级讲师)

编辑部成员:张晓晓 张燕青

前言

本书终于如期与广大读者见面了!在此,本书的两位作者首先感谢朋友们的鼎力支持!同时,我们也非常感谢51Testing软件测试网(上海博为峰软件技术有限公司)一年来的肯定与支持,这次能与51Testing联名合作,是一种缘分,也是一股巨大的动力!

在这一年的时间里,两位作者肩上的担子真的很重:有时间的压力,它凝聚了我们 365天的所有工作之余的业余时间,将这些时间加起来,就是本书的实际编著时间;有精神上的压力,工作任务艰巨,当下班后原本就已疲惫不堪的身躯和灵魂仍然要提起 120%的精神坐在计算机前,一字一字地敲击着键盘进行输入;有责任感的压力,我们从没有想过以“敷衍、草草了事”的态度来完成本书的创作,因为我们深知这会伤害到花了“银子”买书的读者以及两位作者的个人声誉!从整本书的框架构思开始到实际编著内容时,我们都时刻提醒自己!多少次熬夜、多少次反复修稿……一切的一切就是要为了出一本好书,至少我们很肯定这是一本好书,本书是我们的心血之作、100%用心之作,凝聚了春、夏、秋、冬四季轮回的酸甜苦辣!

在写这本书前,我们考虑到了两个大难题。

其一,就是如何才能让读者(尤其是QTP初学者)真正地学会实际应用QTP做企业项目,而且还能灵活应用!光这一点作者就花了相当大的精力,最后得出了共同的结论:写作上“通俗且幽默”。相信大家都有这样的体会,就是拿着一本计算机的技术书或者工具书,看着那些枯燥的代码和文字,往往会有想睡觉的感觉。但在本书中,读者时常会看到和QTP没关系的话题,相信这么做是有很多好处的,因为技术类书籍如果写得太枯燥、不生动,太官方化、太专业化反而会让读者有睡觉的冲动,如果使用通俗的文字,读者理解起来就很方便了,再配上一点点的幽默,读者就会有看下去的欲望,至少不会觉得很累!没有那么多条条框框的限制。

其二,实例素材的收集。我们知道,市面上现有的QTP书籍无非是采用老套的QTP自带的飞机订票系统,都这么多年了,也该换换“口味”了!那个系统不光陈旧也不够真实,和现在我们做的项目出入太大!所以经过讨论,我们两位作者最后达成共识,决定启用“51Testing门户网站”、“51Testing论坛”、“51Testing博客”、“百度”等大型Web网站测试为样板,它们都是最新、最贴近现实、最鲜活的“现成项目”。这样,读者就等同于在边学 QTP边做真实项目。我们提供的模拟项目越真实,读者吸收到的养分就越多,吸收得也越快!讲解中还有意地安排了“循环性的重复”,从而不断巩固知识点!所以只要用心研读,最后一定能掌握写QTP代码的技巧,并能够实际运用到企业的项目中去,这不就是我们学QTP的目的吗?拿现成的代码运行一次是肯定学不会QTP的!另外,作者是期盼着我们用过的实例对象全都发生变化,这样读者也就不能照着书依“葫芦画瓢”了,从而不得不静下心来思考如何去改代码,就不由自主地又变成了积累脚本维护经验的绝佳机会,相信通过一段时间的积累,读者一定会通悟QTP的!

本书的7大特色

1.“三合一”全能读物:教科书、实战项目指导书、高端技术/管理人员参考书。

2.采用QTP10.0 版本,保证读者学到的内容不过时。

3.本书的理念就是“实用”,故所有不实用、项目中不常用的内容全部剔除。

4.本书没有QTP“录制”方面的任何内容,全部是QTP脚本开发的教学与指导。

5.不是一本照抄QTP“帮助文档”的书籍。

6.实例新颖、趣味、符合实际,市面上目前最真实的模拟项目环境。

7.首创的知识巩固练习题配合练习详解,帮助读者学以致用。

关于如何使用好本书(快速了解本书)

并不是每一位读者在买回一本书后都可以很好地利用它的!作者考虑到了这点,所以在此给出一个导向,引导读者快速了解本书,希望能最大化地为每一位读者服务。

本书没有所谓的“篇”的概念,但是,假设要划分为“篇”,作者会分为3个篇章。将第1和第2章归为一篇,将第3章和第4章归为一篇,最后将第5章和第6章归为一篇。下面大致介绍一下这3个“假设性篇章”的功能。

“第一篇”能让读者系统化地学习QTP最实际的应用。整个第1章就是将所需掌握的知识依次讲解,讲解顺序都是精心设计过的。在基本知识掌握后,还需要一些真实项目的经验积淀,那就可以进入第2章的学习了,里面涵盖了大量真实鲜活的模拟项目的例子,以及做项目时需要的一些其他QTP技术,作者讲解这些例子时也不断地在为读者扩展思路,帮助大家举一反三。一旦这两章学通了,一定可以独自承担自动化测试的脚本开发工作!

“第二篇”能让读者深度掌握 QTP,里面介绍的技术虽然不一定每次、每天都会使用,但是要使用时如果你不会就比别人更逊一筹了!这两章一旦学通,可以说是“出师”了,也是一个很重要的跨越阶段!

“第三篇”能让读者有一个层次上的上升。这个提升尤其体现在看待自动化测试的角度上。读我们这本书的设计模式和自动化测试框架的内容,千万别照搬学样,我们的初衷不是让读者模仿,而是借鉴!学会借鉴然后去和自己的测试项目匹配。因为这两章内容是浓缩的精华,就拿“设计模式”来说,这些设计模式都是国外的QTP专家认可的!

另外,本书在第1章、2章、3章、4章节精心设置了习题和讲解,目的就是帮助读者巩固已学的内容,也给读者一些练习的素材,做过这些习题后,读者以后也就知道如何找素材来练习了。建议读者用心完成以后再参考作者的讲解内容,效果更佳!

51Testing 论坛是中国测试界的一个“百家讲坛”,很多测试朋友在论坛中会问各种各样的QTP问题,但是时间长了,发现很多问题其实都是大同小异的,所以在附录内容中添加了“QTP科普问答典藏30例”,它涵盖了一些很值得关注的问题。

本书针对的读者群

自动化测试初学者——深度知悉自动化测试到底是什么,怎么做。

他们可以在本书中掌握自动化测试的技巧、理念,吸取作者的测试自动化经验。

QTP 初学者——学会使用QTP 编程技术。

这本书就是一本非常好的“教科书”,两位作者也是从初学者走过来的,最能体会初学者最想要什么、最需要什么!这本书最适合这部分读者了!

QTP 项目开发人员——提高自身的编程技巧,拓展QTP 知识。

在做项目的时候,如果能在办公桌上备有本书,相信能减少查询百度的次数,且提高工作效率。因为本书中涵盖了各种QTP实用技术,且这些技巧只针对项目中的实际应用。

QTP 技术高手——本书部分高级内容给这部分读者参考、借鉴、补缺。

从第4章开始的所有内容都会帮助到这部分读者。以设计模式举例,一个技术高手不一定擅长此道,本书给出了实战应用。

QTP 架构师——本书第5 章、第6 章内容给这部分读者更多的灵感。

本书的第6章“QTP原创框架设计展示”是作者花了非常多的心血原创的实际框架,并会细致地解析,相信对QTP架构师会是一个很好的参考。

测试经理——若不了解自动化测试和QTP 自动化实施,看完本书就了解了测试流程和技术。

本书能帮助测试经理提高QTP功能自动化测试这块的业务水平。

自动化测试组长——本书的第1 章~第6 章都适合这个角色。

QTP 培训师——这本书给这部分用户最大的便利,这么好的、现成的教科书拿来就能用。

作者认为本书最适合的对象除了初学者就是培训师了,因为本书的一大功能就是“教科书”功能,作者通过自身丰富的培训经验,完全是以循序渐进的理念来指导每一位读者,最后成为一名QTP自动化测试技术高手。

特别致初学者

在学习第1章和第2章时,请务必按章节顺序依次学习,这些章节的顺序都是作者精心设计过的,这样才能事半功倍。

特别致QTP培训讲师

建议教授初学者,请循序渐进地教授第1章和第2章。而面对其他水平的学员,教学顺序不限定。无论哪个水平的学员还是建议教会他们真正举一反三的方法,可以直接引用本书所设置的练习题,也可借鉴后自行设计习题。

本书在写作中,作者已尽力创作,但由于水平有限,加之技术不断更新,难免有疏漏之处,诚请广大读者批评指正,作者的联系方式为:www.51Testing.com/? yujie。

第1章 测试脚本开发从零开始

 

1.1 自动化测试从零开始

阶段要点

• 自动化测试的优势与劣势。

• 引入自动化测试的条件。

• 避免自动化测试的因素。

• 实例解读软件测试自动化。

• 严格的自动化测试流程。

• 自动化测试用例设计详解。

 

1.1.1 什么是自动化测试

1.1.1.1 引言

“自动化测试”,一个耳熟能详的软件测试行业术语、一个绝大部分测试界人员的奋斗目标、一个听上去就很有感觉的名词、一个甚至能牵动未来测试界发展水平快慢的技术。是的,以上说的几点都没有错,它就是软件测试行业中最高端的技术之一,测试自动化技术!它以程序测试程序、以代码代替思维、以脚本的运行代替手工测试。自动化测试同时涵盖各种各样的测试种类,常见的有以下几种:功能(黑盒)自动化测试、功能(白盒)自动化测试、性能测试、压力测试、GUI测试、安全性测试,它们都可以由测试自动化技术来代替手工测试,其实还有很多,作者只是概括了大家都熟悉的软件测试种类,其他的诸如作者曾经收到过这样一个问题,这名测友问:“网络游戏的功能可以引入自动化测试吗?”虽然作者并没有游戏行业的软件开发、测试经验,但是作者确信,网络游戏一样也可以引入测试自动化技术,为什么?因为网络游戏同样是用程序写出来的,只要是一种程序,那么它一定能用程序测试程序、用代码代替思维、用脚本的运行为手工测试代劳!

可以这么说,自动化测试这个术语,每天都索绕在我们的耳边,所以,掌握测试自动化这门技术,对测试工程师来说,是至关重要的,我们并不需要精通每种测试自动化技术,但是,至少我们需要精通其中的一种,只要精通其中一种,相信你在测试这个领域一定会占有一席之地,这门技术能带给你非常大的优势!虽然测试永远脱离不了手工测试,但是,未来测试行业一定会是由自动化测试来引导。这是不争的事实,中国测试行业发展之快也是有目共睹的,如果你现在能掌握这门技术,相信未来的测试路会越走越顺畅,你的测试职业生涯会越来越精彩。

1.1.1.2 自动化测试能做到什么及其优势,你心知肚明吗

万物存在即合理,自动化测试能不断地发展至今,足以证明其在测试领域中有着举足轻重的地位,能切实地帮助项目进度的推动、提高项目的质量和协助测试人员提高工作效率。那么自动化测试究竟有何功能呢?这里归纳了最重要的几点并予以分析。

回归测试更方便、可靠。通常来说,这是自动化测试最主要的任务和特点,特别是在程序修改比较频繁时,效果是非常明显的。由于回归测试的业务流程操作和测试用例是预先完全设计好的,预期结果也是完全在项目人员掌握之中的,将回归测试交给计算机自动运行,可以极大提高测试效率,缩短回归测试时间。这里需要强调一点,上述说的程序修改比较频繁指的是新功能的不断加入,而老功能的逻辑是不变或者很少变化的,不是指整个程序全部或大批量地改动,因为这样是违反自动化测试原理的,在下文也会有类似的讲解。

可运行更多、更繁琐的测试,且快速、高效。自动化测试的一个明显好处是,可以在较少的时间内运行更多的测试。我们知道,有很大一部分业务功能由于业务逻辑极其繁琐(暂时不说有多复杂),使用手工测试往往耗费大量的时间,测试1次、2次、3次可以,但是,如果测试10次以上或者更多呢?当一个测试人员测试同一个业务功能10次以上,几乎可以断定,没有一个测试人员会继续耐心地测试下去。所以,此时自动化测试就能发挥作用,自动化测试的耐心是无限大的,而且计算机的执行速度远比人工快!

可执行一些对于手工测试来说相当困难或根本做不到的测试。比如,对于大量用户的测试并发,不可能同时让足够多的测试人员同时进行测试,但是却可以通过自动化测试模拟同时有许多用户并发点击某一功能,从而达到测试的目的。再比如,人工不可能 24 小时不眠不休地进行测试,但是计算机则不用休息。当然,类似的例子还有很多,无法全部列举出来。

更好地利用资源,使资源的使用更有价值。将繁琐的任务自动化,可以提高准确性和测试人员的积极性,将测试技术人员解脱出来投入更多精力设计更好的测试用例。有些测试不适合于自动化测试,仅适合于手工测试,将可自动化测试的测试自动化后,可以让测试人员专注于手工测试部分,提高手工测试的效率。在引入自动化测试后,测试人员的工作很大一部分可以交给计算机,而自己则解放出来,将精力投入新功能或者测试更深的业务逻辑,争取发现更深层次的缺陷,能做到这些,自动化测试可以说功不可没。

具有一致性和可重复性的特点。由于测试是机器自动执行的,每次测试的结果和执行的内容与操作的一致性是可以得到保障的,从而达到测试可重复的效果。机器可以按照相同的轨迹不断地执行测试并丝毫没有差错(即使错了也可以自动解决),但是人不能!

自动化测试脚本完全具有复用性。由于自动化测试通常以脚本的方式来实现,这样在不同的版本之间,就有可能只需要做少量的维护甚至不做任何修改,实现在不同的测试版本中使用相同的测试脚本执行相同的测试用例。

使软件更有信任度。由于测试是由计算机自动代劳的,所以,不存在执行过程中的疏忽和错误,完全取决于测试的设计质量。一旦软件通过了具有说服力的自动化测试后,软件的信任度一定会大大增加。

多环境下测试。我们知道,一个系统往往会被要求能支持各种不同的环境并稳定运行,但是这么多不同的环境,比如常用浏览器有IE6、IE7、IE8、FireFox等,系统有Windows 2003、Windows XP、Windows Vista、Windows 7等,甚至还有杀毒软件,如卡巴斯基、360、诺顿等,那么多的环境组合,如果每一种环境组合我们都需要花人力、物力去把功能测试一遍的话,估计研发周期至少得增加10倍!在这种情况下,自动化测试又可以完全发挥其优势与作用了,由计算机去代劳,在不同的环境组合中执行测试。

1.1.1.3 自动化测试无法做到的事及其劣势分析

当然,自动化测试不是万能的,它的能力仍然是有限的。自动化测试同样有着各种各样的缺点和无法做到的事情。不过,人类是不断在进步的,测试自动化技术随着人类进步的步伐也一定会越来越强大。下面同样归纳了最重要的一些自动化测试的劣势以及它力不能及的事情。

永远不可能完全取代手工测试。自动化测试不能完全替代手工测试,这已经是业界中不需要再争辩的事实了。自动化测试无法做到手工测试的覆盖率。不是每个测试用例都适合转换成自动化测试用例的。另外,复杂性极强的操作也只能通过手工测试来完成,如果将这个复杂的操作写成代码那将会是件大麻烦事。还有一个例子也能证明,就是比如我们当前需要验证页面上的布局是否正确,那试问这该如何写成脚本代码呢?

无法完全保证测试的正确性。上面也说到了,自动化测试是由测试脚本组成,它的核心仍然是代码,说的简单点,自动化测试就是程序测试程序。我们知道,是程序就一定会有缺陷,所以,不能保证测试工程师开发的脚本就完全 100%没有缺陷,如果代码中出现一个小小逻辑错误,哪怕一个条件判断的误写也会导致测试结果完全出错。当然,对于一个有经验和优秀的自动化测试开发工程师来说,大多数的错误还是会在脚本调试中避免的。

手工测试能发现的缺陷远比自动化测试多。可以这么说,有85%的缺陷是归功于手工测试,而只有15%的缺陷归功于自动化测试(注意:这个标准并不是随便说的,而是由自动化测试专家共同总结得出的一组数据结论)。而且在这15%中,大约只有0.1%不到的缺陷属于新缺陷。的确,自动化测试几乎是无法发现新缺陷的,自动化测试大多是用来发现曾经发现过的缺陷在每个版本下有没有重新出现。当然,我们情愿自动化测试永远不要找出缺陷!自动化测试更适合缺陷预防而不是发现更多缺陷。请记住,自动化测试最大的用途就是回归……再回归。

对测试质量的依赖性极大。自动化测试的运行首先要建立在版本测试质量(在这里基本指手工测试质量)稳定的大条件下,如果当前版本的测试质量不够稳定,运行自动化测试将会非常不顺利,几乎是一种无用功和白白浪费时间的行为。

测试自动化可能会制约软件开发。由于自动化测试比手工测试更脆弱,以及脚本维护会受到限制,从而制约软件的开发。

自动化测试工具是死的,它本身没有任何想象力。自动化测试是无法做到像人类一样随心所欲地创造的,自动化测试的好坏,完全取决于自动化测试负责人和测试开发工程师的思想与技术,和自动化测试工具没有任何关系,工具是没有思想的,所有的操作全部由人通过输入代码的方式告诉工具它该怎么做。

成本投入过高,风险大。自动化测试需要很大的成本投入,并且如果没有良好的成本分析与控制手段以及自动化测试计划与执行过程控制,那么失败的自动化测试案例数不胜数,导致企业白白浪费人力物力还得不到任何回报。

自动化测试对测试人员的技术要求较高,对测试工具同样有一定要求。自动化测试对测试工程师来说必须有一定的开发技术背景,开发技术越高则写出来的脚本质量也就越高、越有技术性和想象力。不是每个测试工程师都适合或有能力开发质量好的测试脚本的。同样,也不是每一个测试工具能真正地被使用在真实的项目中并驾驭项目的,也没有听说过有一个自动化测试工具能做到适合每一个项目。

1.1.1.4 何时适合引入自动化测试

在之前的章节中,通过总结和分析,相信读者已经对自动化测试的特性和优劣有了一定的了解,接下来,分析在实际项目中关于自动化测试成败的点点滴滴。

在我们的自动化测试中,必须让读者知道哪些情况下才适合把项目的系统测试交给自动化测试来完成。但是,如果不能善加利用,则给自己或者组织造成的后果还是比较严重的。下面让我们一起认知何时才比较适合做软件测试自动化!

项目周期长,系统版本不断。如果你目前所在测试的项目(或系统)是属于一个周期比较长的项目的时候,可以说,的确非常适合引入自动化测试,把大量的回归测试托付给测试自动化是一个比较明智的选择。还有一种根据是从系统的版本数得来的,曾经测试领域专家有过相关的研讨并最后得出结论,一般自动化测试耗费的时间是手工测试的6~10倍,所以,如果你所在的项目(或系统)版本数在10个以上,那么,引入测试自动化也同样非常的睿智,并且和之前的项目周期综合下,时间越长随之而来需要测试的版本就会越来越多,这样,自动化测试可以发挥它最大的作用,给企业带来各方面的利益。

需求变更不频繁。当项目的需求非常稳定,不会经常出现变更的时候,此时也很适合引入测试自动化。

系统中的测试对象基本可以正常识别。一般来说,自动化测试的基本要求或者说自动化测试工具对系统的基本要求就是对象的识别,一个自动化测试工具的好坏评判最基本的标准就是,是否能够识别更多的系统控件以及对无法识别的控件能否提供各种解决方案或自定义开发各种控件的识别代码。

系统中不存在大批量第三方控件。有实际项目经验的读者一定会发现,无论什么系统,B/S架构的也好、C/S架构的也行,多少存在一些第三方控件,但是,如果这些第三方的控件数量不多的话,经过详细的计划与评估后,完全可以引入测试自动化,当然,如果第三方控件数量庞大或者形式种类庞大的话,就会带来很多麻烦,在下文中也会提到。

需要反复测试,如可靠性测试需要进行上千次的系统测试。在我们的1.1.1.2 项目的第一条例子中,提到过类似的情形。在项目中,如遇到这种情况,从理论上讲是相当适合使用自动化测试策略的,当然,前提条件是有能力把自动化测试做好,如果遇到这种情形,测试自动化实行最后成功的话,一定能给整个项目团队带来“丰功伟业”!

1.1.1.5 何时避免展开自动化测试

在 1.1.1.4 节中,归纳了自动化测试的适宜条件,但是万物都有另外一面,自动化测试也有很多禁忌,作为一名测试工程师或者未来的自动化测试工程师来说,如果触犯了禁忌还要执着地做下去,后果也只有一个,就是自讨苦吃,给企业、项目团队带来损失,使得领导以后再也不信任自动化测试,使自己对测试自动化技术更加迷茫!接下来,作者以自己多年自动化测试实战经验以及学习经验,一定要告诉读者,在自动化测试中,哪些是犯了大忌的,读者务必吸取前人的教训,扬长避短,如果以后在项目中和以下任何一条有冲突,千万不要开展自动化测试。

项目周期短,需求变更频繁。当你的项目周期不是很长的情况下,请不要引入测试自动化,因为这样的话,不但收不回成本,而且会延长产品的发布时间,并且这样的行为是毫无意义的!作者在1.1.1.3小节中的第一条已经提到了。自动化测试的成本计算方式及其计算实际参照,在这里则不再多加阐述。当然,还有一个问题,相信有项目经验的读者一定会碰到过类似的问题,即使这个项目是一个长期的项目,但是客户经常性地更改需求,甚至时常更改老功能的业务逻辑。这种情况下,即使周期再长的项目也最好别引入测试自动化,因为,即使你有再好的自动化测试方案和执行技术,但你始终赶不上客户变更的速度,最终仍然还是会放弃,因为永远在收拾“烂摊子”!

在软件版本还没有稳定的情况下。当你准备引入测试自动化时,请先确定你所在的项目,版本功能是否已经稳定,如果版本功能还不是很稳定,主功能或大量的功能有被重新更改的可能性的话,务必暂时缓一缓,不要随意地开始自动化测试之旅。

没有明确的项目测试自动化计划、措施和管理。在这里,作者根据多年的项目自动化测试实战经验可以用很确定的态度与语气告诉读者,软件自动化测试和软件开发工程是一脉相传的!作者在此不阐述软件开发工程的基本概念,但是作者一定会强调,在自动化测试的开发过程中,一样需要通过严格的开发计划、版本管理、代码管理等一系列相关措施,兢兢业业地做好每一步工作,踏实地管理和控制好每一个环节。自动化测试脚本不是一次性的,而是需要长时间维护下去的,如果事先没有制定良好的测试方案,实施过程中不严格根据方案执行,开发完毕后又不做任何改进或提出各种优化方案等,那么你说,最后项目自动化测试会成功吗?

领导不支持。目前,较多企业,特别是中小型企业的高级管理人员还是没有能力或者没有信心可以将软件测试自动化做好。在这种情况下,首先,作者认为还是先和领导沟通好,取得他们的支持、理解与信任后再引入测试自动化比较妥当;没有领导的肯定与支持,自动化测试之旅一定是无法顺利展开的,最终也达不到终点,多半情况下会中途不了了之,如果这样的话,还不如不要引入测试自动化呢。

多数对象无法识别以及脚本维护频繁与艰难,二者有其一,自动化测试注定失败。又一次提到了这个说法,因为它的确太重要了!希望读者能真正地通过作者一次又一次地重复,真切地了解到这个自动化测试的重大问题。根据前文的不断讲述,作者再总结一下,如果项目中存在大量无法识别的控件(这种情况基本是发生在系统中存在大量的第三方控件)或者没有获得相应的对象识别插件,是没有办法写出自动化测试脚本的。当然,对象的识别不一定要靠插件,还有其他解决方法,比如SDK插件扩展,或者让开发人员提供相应的DLL来识别等,但是,如果有一半的插件不能识别,那么再强行为之,耗费的人力、物力将会有多大?估计能够重新开发一个新项目了。脚本维护频繁是直接和前文所述的需求变更频繁有关的,需求一直在变,自动化测试工程师只能跟着将脚本永无止境地变化下去,直到头晕目眩、直到大量测试开发工程师受不了如此的“虐待”而离职。最终,自动化测试正式宣布“失败”!

 

1.1.2 严格的自动化测试流程

1.1.2.1 影响自动化测试成功与否的关键因素是流程

作者通过多年的自动化测试实战经验认为,必须将整个自动化测试过程看成一个软件开发项目的过程,因为测试脚本是由代码组成的,而测试代码又是自动化测试的根本。有效地开发并维护良好的测试脚本,是自动化测试过程的重中之重。但是,想要行之有效地管理好这些测试脚本并不是容易的事情,就像管理好项目代码一样!所以,自动化测试过程就是一个软件开发的过程,需要经历各类分析、测试计划、框架及测试用例设计、脚本开发、测试执行、提交报告、脚本维护、版本控制等一系列繁琐的过程。图1-1所示是作者经过的一些成功项目自动化测试后总结并描绘的一张自动化测试流程图。

图1-1

接下来,根据“图1-1”逐一讲解每一个关键过程(阶段),让读者明确自动化测试流程及其中的一些细节。

1.合理的自动化测试切入点

通常,项目只有在经历了完整的系统测试后才算具备了基本的引入测试自动化的条件。于是,一般也就在这个时间段,项目经理与测试经理才会以此定为自动化测试开始筹划与准备的时间点。到目前为止,绝大部分的公司都以系统测试完成为标准来作为自动化测试的切入点,因为在之前的任何阶段中都不是非常适合做自动化测试。

2.测试自动化分析

在具备了可自动化测试的基本条件后,仍然需要默认自动化测试工作展开的难度之大!我们必须通过各种分析来确定是不是要继续将测试自动化做下去。根据作者在完成了多个自动化测试项目后总结出的经验(有成功的经验、同样也有失败的经验),我们在做测试自动化分析时最该做的就是以下3种。

(1)可行性分析。

在进行项目自动化测试之前,第一步就是要确认其可行性,是否可以实行测试自动化。作者认为,在常见的不可行因素下,如果出现其中任何一种,自动化测试工作都是不应该展开的,项目常见不可行因素如下。

项目时间紧迫。如果项目进度很紧迫,开发周期的时间表很紧,每次交付间隔时间很短,你就没有时间进行测试自动化,也就不要考虑自动化测试了。

项目需求变幻无常。测试负责人应该及时和PM或专门的需求人员沟通来获得最直接的项目方面、客户方面的现有情况以及未来情况,从而最终通过分析来确认是否要进行自动化测试。因为PM和需求人员往往是对项目现今和未来的发展或对客户的思想及个性最了解的人群。举一个例,作者曾经经历过一个项目,是属于比较大型的长期项目,但是最终这个项目并没有展开自动化测试。为什么?因为这个项目的需求由于总是要“赶时髦”,所以一直在不断变化,那么即使它再耗人力、物力,作者所在的测试团队也只能老老实实在每个版本下来后去进行大批量的手工回归测试。当然,现在看来作者非常庆幸,在这个项目中放弃了自动化测试的念头,因为刚上线那时,作者就和PM进行了沟通,得知了这个项目以后会是一个需求时常变化的项目。如果那时候引入测试自动化的话,作者相信基本现在已经属于一个烂尾楼工程了!

项目周期短。如果你觉得在写完所有自动化测试脚本后,这些脚本只能仅仅为你服务几个(6个或更少)版本,不用多考虑了,放弃自动化测试吧。

自动化测试工具对系统的有效性。如果上述的前3 个和你所在的项目不沾边,那么请再看看这条因素。我们知道,想要开发自动化测试脚本,那么必须具备一款匹配的自动化测试工具,可以是开源的也可以是商业化的,甚至是自主研发一款。此时,就需要确切地了解这款测试工具能否应付项目中的需要。举个例,假设你所在的公司购买了一款商业化的自动化测试工具,项目系统中全部是一些Java控件,但是测试工具自带的插件中又不包含Java控件的识别插件,那么此时就算拥有这款自动化测试工具,但由于无法有效地识别到项目中的控件,所以,对于项目来说是毫无作用的。

(2)抽样demo分析。

通过可行性分析后,接下来要做的就是一个做demo了,等待demo完成后,可以再次通过分析看看自动化测试工作能否顺利地展开下去,因为 demo 已经是一个实体案例,所以,可以完全通过透析demo来发现是否存在技术上的致命问题。通常在demo完成之后,有经验的自动化测试工程师或组长就能对这个项目的自动化测试工作有一个大体的把握了。换言之,可以把demo看成更深层次的可行性分析,一旦通过了抽样demo分析,自动化测试就可以展开了。关于 demo 的选取,一般直接选择冒烟测试用例(大冒烟)写成测试脚本后执行,检查脚本是否能够成功运行通过,已设计的测试点是否全部执行到即可。

(3)测试需求分析。

到了测试需求分析这一步,分析的就不再是能否在项目中引入测试自动化了,而是在为下一阶段定制具体计划打下基础。测试需求其实就是测试目标,也可看做测试自动化的功能点,也就是自动化测试工程师想完成的任务。比如我们需要分析项目中具体哪些测试需求(功能点)准备进行自动化测试。一条测试需求可以包含多条自动化测试用例,通过测试需求分析来判定项目中测试自动化要做到什么程度。举个例子,在自动化测试用例的设计上,大体是以正向、反向(见小提示)划分的,一般在自动化测试中,优先考虑实现正向的测试用例后再去实现反向的测试用例,而且反向的测试用例大多都是需要进行分析然后筛选出来的,因为反向的测试用例实在太多了。我们知道,自动化测试是不需要也没有必要做到100%覆盖率的。所以,在测试需求分析这个阶段,确定测试覆盖率以及自动化测试粒度、测试用例上的筛选等都是重点工作。

小提示

自动化测试用例设计中的“正向”和“反向”指什么?通俗点讲,“正向”测试用例就是正常的业务操作流,几乎没有什么非正常情况操作融入在其中。反之,“反向”测试用例就是异常的业务操作流。我们可以想象一下,做出来的软件是给谁用的?当然是给用户使用的,一般情况下,用户在基本使用上不会像测试工程师那样去“破坏”,他们只关注软件的功能是否好用、是否有异常、是否有差错。所以,“正向”的测试用例就是只针对正常的操作,不会去考虑异常情况,当然,也必须是自动化测试脚本优先要写出来的。待把这些正常的业务操作的测试脚本全部完成后,才去考虑加入部分最重要且优先级最高的“反向”测试用例进去,比如一个注册页面中某表单的填写,用户一样比较关心系统对错误的处理情况,这时候,就需要把自动化测试用例设计成“反向”的,然后加入到回归测试中。不过,“反向”测试用例实在太多,如果全部都写成脚本,是没必要也不符合自动化测试的特性。所以,才需要分析、筛选、决策。

3.测试计划定制

在经过了测试需求分析阶段后,项目PM和自动化测试组长就该正式起草正式方案了。写一个优秀、完善、精致的测试计划是必须的工作。当然,这里不会讲述测试计划是如何写的。只是要告诉读者,测试计划的质量和以后的工作顺利进展有着密切的联系,能越早地把各种情况都考虑在计划中对以后自动化测试项目的展开都是很有利的,想要使得自动化测试最终成功,也必须踏踏实实抓住每一个环节,测试计划定制阶段如果能做好,则可以看作是一个良好的开始。而且,通过作者的经验发现,自动化项目的测试计划越全面,后期越能够循规蹈矩的去实施,自动化测试的成功率就越高;如果自动化测试计划设计不周全,靠后期去完善、补充,基本上这个自动化测试项目就成了一个实验项目。

4.自动化测试设计阶段

在这个阶段,把它分为两个核心部分。第一个部分就是自动化测试框架,第二部分就是自动化测试用例。

(1)自动化测试框架设计、开发与搭建。

自动化测试框架的好与坏直接影响以后项目的实施。作一个恰当的比喻,一个软件项目如果没有一个好的架构,那这个项目也不会好到哪里去,自动化测试框架对于整个自动化测试项目来说就相当于一个架构,这个架构越好、功能越强大和实用,那就可以给今后整个自动化测试项目的工作过程带来更多的好处。不过,国内目前很多自动化测试框架都过于浮夸,很多工程师为了把自动化测试框架设计得更加强大,开发了一个又一个的“强大”功能,其实到头来只是“花拳绣腿”,根本和自动化测试项目无法兼容!他们也忘了做自动化测试的基本目的是“测试”两个字,把自动化测试框架搞成了一个新项目来开发,真是得不偿失!自动化测试框架其实不止是一种程序,它也应该是、一种思想、一个规范。测试框架的好坏判定应该以实用、适用、扩展性强、使用范围广、稳定、思想先进为先,绝对不能以“强大”却又背道而驰的可用功能为主!在本书的自动化测试框架章节中,作者会把自己原创的自动化测试框架完全奉献给每一位读者。

下面,作者也来谈谈是如何看待“自动化测试框架”这个“香馍馍”的吧。自动化测试的基本概念有以下两点。

自动化测试框架是能保证测试的分布执行,脚本模块化,数据驱动,日志分析,错误截图,报表回收,共享对象库,公共函数库,环境配置,统一设计模式,异常处理,场景恢复等的一个无人值守的,针对每个独立项目的测试框架。

自动化测试框架就是一个“舞台”,可以让所有自动化测试工程师在“舞台”上表演,没有这个“舞台”,自动化测试工程师就只能单干,在一段时间内是可以的,但是长期发展后会遇到很大的瓶颈,这时候就需要自动化测试框架来突破瓶颈。

(2)自动化测试用例设计三部曲。

自动化测试流程其实跟手工测试流程差不太多,要先编写测试用例,只是被叫作自动化测试用例而已。先设计好自动化测试用例,再严格根据设计完成的测试用例编写测试脚本,这是一种规律、一个过程。

自动化测试用例设计和手工测试用例设计是有明显区别的。手工测试用例是从无到有的过程,而自动化测试用例不是的。自动化测试用例是有参考物的,它就是手工测试用例。它有时候可以直接拿来用、有时候需要稍加修改,作者把整个自动化测试用例设计过程分为 3步,我们就把它叫做自动化测试用例设计三部曲。

筛选手工测试用例的过程。自动化测试用例设计应该是拿来主义,首先要根据测试需求分析阶段得出的“分析结果”筛选出所有要被“测试自动化”的手工测试用例。在全部筛选完毕后,再分成两部分,一部分是可以直接二次复用的手工测试用例,不要客气,直接拿来即可。另外一部分则要经历下一个过程。实际上,大多数还是需要经过改造的,毕竟自动化测试用例的设计方法和手工测试用例的设计方法有点出入,哪怕是冒烟测试用例多少也要稍加修改。

转换手工测试用例的过程。把无法直接复用的手工测试用例部分依据自动化测试用例设计方法与规则转换成自动化测试用例。一般转换要素无非两种,一种就是测试用例的格式和规则,另一种就是优化自动化测试业务流程。自动化测试业务流程和手工测试业务流程还是有一定区别的。自动化测试业务流程更精简、严格(是一就是一,是二它就绝对不应该是三)!

新增&补充自动化测试用例的过程。最后就是新增和补充一些手工测试用例没有涉及的自动化测试业务流程了,请严格根据自动化测试用例设计的方法和规则进行增补(关于“自动化测试用例设计”请见下一章节内容)。

自动化测试用例经过“三部曲”的“洗礼”后基本算是搞定了,但是读者千万别忘了今后我们仍然会重新回到这个阶段,经历自动化测试用例的维护、不断优化的过程。

5.测试脚本设计与开发

世间万物皆有灵魂,而自动化测试的灵魂则是测试脚本的设计与开发。自动化测试项目的开发过程的重要性绝不亚于软件项目开发过程。脚本开发阶段也是整个自动化测试流程中最关键的一个阶段。

在自动化测试中,测试脚本大致可划分为5种。

(1)线性脚本:通过录制直接产生的线性执行的脚本。

(2)结构化脚本:具有顺序、循环、分支等结构的脚本。

(3)可共享脚本:可以被多个测试用例使用,被其他脚本调用的脚本。

(4)数据驱动脚本:测试数据和业务流程控制分离的脚本,通过读入数据文件来驱动流程进行的脚本。

(5)关键字驱动脚本:脚本、数据、业务分离,数据和关键字在不同的数据表中,通过关键字来驱动测试业务逻辑。关键字驱动脚本的特点是,它看起来更像描述一个测试用例在做什么,而不是如何做。

从上面5种不同的脚本特性可以看到,自动化测试脚本开发的发展是和软件工程思想的发展一脉相承的。软件开发的模式从面向计算机、到面向过程,再到面向对象、面向服务,是一个从底层到高层、从具体到抽象,复用的粒度从细到粗的发展过程。而软件开发中的模块化、层次化、松耦合等思想对自动化测试脚本的设计与开发都具有借鉴意义。

作者认为,如果作为一名自动化测试新手,应该多学习并吸取前人的经验,在学习过程中乃至平时的工作中不断地模仿、深刻钻研,钻研后的尝试最后达到融会贯通。同时,作者也总结了几点关于自动化测试脚本开发的经验与感悟,希望能给读者更多的参考。

自动化测试脚本代码必须严谨、规范。

自动化测试脚本是参照自动化测试用例开发出来的,测试用例即是开发参照物。

发挥自己的想象尽一切可能使自动化测试脚本更智能、高效、稳定、复用性高。

开发过程中多利用程序插桩+断点,检查业务组件是否存在缺陷或代码是否存在漏洞。

自动化测试脚本开发完毕后,至少运行成功3次以上,方可认为脚本已经没有问题。

此外,项目中也必须具备一款优秀的代码版本管理软件来管理好每一个测试版本的自动化测试脚本,这也是自动化测试项目中非常重要的环节。

6.自动化测试执行

这个阶段可以说已经是自动化测试流程中的后期阶段了,所有的自动化测试脚本全部开发完毕并发布后会进入合并联调阶段,脚本联调(见小提示)成功后方能进入这一阶段。

小提示

“脚本联调”是很关键的一个时期,联调如果不通过是无法进行下一个环节的,毕竟都到了这个阶段了,已经花了许多工时了!想要联调的时候顺利通过,功夫还得花在平时!平时写代码规范点,严格按照规范标准去写代码,到了这个阶段遇到的问题就少,即使发生了也好解决。

这个阶段的开始也就意味真正的自动化测试开始了。会很开心,辛辛苦苦写的脚本终于有了用武之地,系统开始进行“自动化测试”!既然是自动化测试,那当然可以由计算机来测试啦,人就不用管了,而且出了问题计算机自动会帮我们解决并重新自动测试。

(1)无人值守的测试。

使测试自动执行,大致会经历以下步骤。

环境搭建、部署与配置。

首先搭建一个自动化测试执行环境是必不可少的,这部分的功能往往以自动化测试框架来支持,此外市面上还有很多类似的批量脚本执行工具也可以做此类的操作。如果是自动化测试框架支持的话,通常需要根据实际情况做相应的配置使其生效。

自动化测试用例和测试脚本互相绑定。

接下来的工作就是将自动化测试脚本与当初设计的自动化测试用例做关联和绑定了(这部分在前期也可以做)。

自动化测试用例执行顺序排列与组合。

在完成了上面的工作后,就可以创建一个测试集,在测试集里添加各种各样的自动化测试用例。当然,根据业务实际情况,测试用例的先后排列顺序和各种组合是非常有讲究的。

(2)异常处理和场景恢复。

俗话说:“天有不测风云”。谁都没法预料在自动化测试过程中会碰到什么问题,系统服务器崩溃?电脑卡机?服务器无响应?如果发生了这些情况怎么办?如果在白天的话,自动化测试工程师守候在执行机器旁边那还好,重新花时间整理。那如果晚上呢?自动化测试工作就要被迫停止了?当然不行!这个时候,一个优秀的异常处理与场景恢复机制就显得尤为重要了,有了这个机制,我们才能放心地将测试交给计算机执行。在本书以后的章节中,也会详细和精辟地分享这方面的具体内容。

(3)一个自动化测试执行实例。

在本阶段讲解的最后,作者举一个 QC 自动化测试框架(HP 公司产品 Quality Center,一款集测试解决方案、测试流程管理、缺陷管理的工具,其本身也是一个自动化测试框架)的例子,其实也算是一个完整过程。

我们将测试脚本上传至QC服务器并与相应的测试用例绑定。最后,可以生成一个测试集,测试集里可以导入之前设计的测试用例,如果导入的用例和脚本有过绑定,则脚本也随之自动加载到测试集中,只需要点击“执行”按钮,QC就会自动执行脚本,开始测试了。

如果在执行过程中发生意外情况,只要预先设置了各种异常情况及处理应对方式,QC就会自动进行处理,并把测试场景恢复到预置的状态重新自动执行测试。

等测试集中的测试用例全部运行完毕后,QC 就会显示这些测试用例的运行结果并生成图表,然后自动将缺陷提交到服务器中,方便测试工程师了解自动化测试运行以及完成的情况乃至发现的缺陷情况。

7.提交自动化测试产物

这个阶段,是对自动化测试项目开展、实施的反馈。通常,在自动化测试执行后,大致需要提交执行情况、测试结果、分析报表、测试报告、质量情况等(具体每个项目都会有所不同)。其实细心的读者应该能察觉到,在上面那个阶段讲解最后的实例中,已经有这个阶段的影子了。

值得开心的是,在提交了自动化测试产物后,自动化测试就算大功告成了!接下来,通常需要做一些会议总结、经验分享、自动化整体测试过程分析、自动化测试项目改进建议等工作,为了在后续的版本使自动化测试能取得更大的硕果。

8.测试脚本维护

其实到了“提交自动化测试产物”这个阶段,一个自动化测试流程就算是结束了。测试脚本维护阶段不能单纯地被看作是一个阶段,因为测试脚本维护的工作是时刻穿插在各个阶段中的(“第五阶段 测试脚本设计与开发”开始)。严格来讲,每个阶段都在做测试脚本维护的工作。只是,测试脚本维护对于整个自动化测试项目非常重要,也是需要做最久的一项工作,所以,作者将其单独列为一个阶段来讲解。

自动化测试脚本维护也是一个持续性的优化过程,总是不断地在优化、改进、修正。作者觉得,做自动化测试最多的还是“维护”!不值得“维护”的自动化测试项目是不值得立项的!

1.1.2.2 自动化测试项目“标配”

了解了自动化测试流程的繁琐与严格后,再了解以下自动化测试团队的人员标准配置。从目前国内企业实际角度出发,算上自动化测试项目管理人员,我们以5人的团队为例。先让我们看以下这5人团队内存在的角色及其角色定义。

自动化测试组长:自动化测试团队的最高管理,拥有发言权。负责自动化测试项目从自动化立项到进度实施,到验收报告等整个测试流程;负责团队人员调度与管理;负责与上级领导、项目经理、手工测试负责人沟通与协调,并带领整个自动化小组工作。

高级测试开发工程师:团队中技术最牛的角色,通常负责自动化测试框架的设计与搭建;负责自动化项目实施过程中各类技术难点的解决;负责公共数据的提炼和开发,如公共函数库等。

自动化测试用例设计人员:由团队中对业务和手工测试情况最熟悉的人员担当。负责自动化测试用例的设计开发工作,及今后的测试用例维护工作;负责测试脚本的验收工作,监督测试脚本业务逻辑是否与设计好的自动化测试用例一致。

脚本开发人员:“战场前线”人员。负责自动化测试脚本的设计与开发;负责脚本合并联调工作;负责后期的脚本维护工作。

自动化项目库管理人员:类似文职人员,可以没有代码开发经验。负责整个自动化团队日常工作中的文档变更记录的整理、公共对象库管理、代码版本管理及公共函数库管理等。

基本职责为。

A某:自动化测试组长。

B某:高级测试开发工程师。

C某:自动化测试用例设计人员。

D某:脚本开发人员。

E某:自动化项目库管理人员。

接下来,就让我们看以下5人团队怎么样人员配置(注:一人可同时兼任多种角色)吧。

自动化测试组长:1人次(A)

高级测试开发工程师:1~2人次(B、A)

自动化测试用例设计人员:2人次(C、E)

脚本开发人员:3~4人次(D、A、B、C)

自动化项目库管理人员:1人次(E)

以上就是一个5人自动化测试小组的标准配置和角色划分,仅供读者参考。

 

1.1.3 自动化测试用例设计详解

通常,在项目的测试过程中,测试工程师都会首先获取测试需求,接着熟悉测试需求,等待测试计划产出后,编写和设计测试用例,一般测试工程师都会根据事先设计好的测试用例来验证实际结果是否符合预期,包括后期的回归测试。而自动化测试项目同样也有这样一个流程,需要自动化测试工程师首先分析测试需求,产出自动化测试计划,设计好自动化测试用例后才能开始进入后续的脚本设计开发阶段。那么,既然要写自动化测试用例,有些读者可能会问,不是有手工测试用例吗,为什么还要去完成自动化测试用例?为什么不能用手工用例来直接替代自动化测试用例呢?它们之间到底有什么区别呢?自动化测试用例的设计原则到底又是什么呢?在上一章节中,内容虽有涉及,但作者并没有作细化介绍,因为自动化测试用例设计是一个非常重要的环节,所以必须单独列为一个章节进行系统化的解析。

很多公司在实施自动化测试的过程中,往往会把所有的手工测试用例作为自动化测试用例,并且直接进行脚本的开发工作,甚至有些公司不写自动化测试用例,直接想当然地开发测试脚本,这些都是极其不规范的做法,甚至很有可能是导致最后自动化测试项目失败的最大原因。那么问题就来了,为什么不能使用手工测试用例完全替代自动化测试用例呢?有以下几点原因,同时也是自动化测试用例的设计原则。

原则1:自动化测试用例的范围往往是核心业务流程或者重复执行率较高的。

在选取自动化测试用例范围时,很多测试工程师或者上级领导可能心里会过分依赖自动化测试,会认为自动化测试就应该覆盖所有的手工测试用例,自动化测试的覆盖率就应该达到百分之百。其实恰好相反,这样的想法往往会导致自动化测试最终失败。在一些大型项目中,往往测试用例的数量会很庞大,而且如果遇到一些繁杂的被测程序(特别是C/S 架构),脚本开发工作往往会相当耗时间,并且很多测试用例甚至根本就不能通过自动化来实现。举些例子,现在很多公司自动化测试都是刚起步,对自动化测试的了解程度只是停留在字面上,在公司对测试也不是非常重视的情况下,当然不太愿意去花精力招一个具有自动化测试开发经验的工程师,很多还是停留在使用工具的录制回放功能来完成自动化测试。正是存在这样的技术限制情况下,往往在实施中,会出现很多录制回放不能解决的问题,测试工具完全无法识别测试对象,无法识别一些特殊的加密测试控件。还有,如果项目的变更频率,测试用例数量大的话,增加了后期的维护工作量等,都是造成最终失败的一些隐患。投入越大,损失越大。因此,往往我们会选取最核心的一些业务路径或者是重复执行率较高的一些手工测试用例进行自动化测试,这样能够充分发挥出自动化测试的优势。

原则2:自动化测试用例的选择一般以“正向”为主。

手工测试用例分正常情况和异常情况,在设计的时候,可能往往会去设计很多异常情况来验证程序是否有Bug,并且一个正常情况的测试用例往往会对应几十个非正常情况的测试用例,而每种异常情况的测试用例都会有各种各样的预期结果。在自动化测试中,很多人喜欢将正常情况称为“正向”;反之,异常情况则称为“反向”。下面,我们试想以下,如果将这些异常情况全部转化、反应到自动化测试脚本中,那肯定需要非常繁琐的判断才能做到。这个对于自动化测试工程师来说,其现有的工作量还是今后的脚本维护量都是不可小视的。对于整个自动化测试项目来说,如果每个异常情况都要写进脚本中,那真的是花了大价钱买一堆小东西,小东西真正能发挥大作用的毕竟很少。因此,真正在自动化测试项目实施中,往往会舍弃反向用例,个别比较重要的除外。使每个东西都能发挥其最大的作用才是企业最想看到的。功能自动化测试主要还是用于回归测试,回归测试的目的就是保证新增功能后老功能是否能够正常继续运作。而自动化测试则是让测试人员从繁琐又枯燥的重复手工测试中解放出来,这就是目的和目标。

原则3:不是所有手工测试用例都可以使用自动化测试来实现的。

这里纠正许多测试从业人员的一个错误观念,刚接触测试自动化的普遍都会认为手工测试用例全部要转化为自动化测试用例,但是在真正实施的时候,却发现很多测试用例是自动化无法实现的,或者有些测试用例根本就没有必要去自动化的。例如,有些用例会牵涉到硬件设备辅助的,最简单的例子就是用例执行过程中需要使用刷卡机才能获取卡号信息(如果有技术能力,当然不排除自行开发接口供测试工具调用,但毕竟能有技术实力做到这一步的不多,能有这样的重视程度的更不多);再比如,有些测试用例是需要与合作机构进行互动联调,联调时是需要和对方实时沟通,以及根据具体情况给予响应的,这些情况多数还是只能使用手工人为地来完成。当然,决定是否转化为自动化测试,必须事先有一个规范文档来定义哪些是需要转化为自动化测试哪些是不需要的,否则测试工程师就会不知所措,没有一个标准。一旦有了这个标准,自动化测试工程师就可以严格按照文档里的流程去完成需要转化部分的自动化测试用例的脚本开发工作了。

原则4:手工测试用例可以不用回归原点,而自动化用例往往是必须的。

很多有经验的自动化测试从业人员一定有这样的经历,很多时候脚本写完后,第一次执行没有任何问题,而第二次执行时立刻就会报错,原因就是没有回归原点。所谓回归原点就是执行的测试用例最终需要恢复其在执行前的初始状态,如果没有回归原点,就会把此脚本称之为死脚本。举个最简单的例子,比如添加用户功能,我们都知道每个用户名都是唯一的,当写完一个添加用户的脚本之后,执行第一次没有问题,因为执行前此用户还不存在,但是当执行第二次时,程序就会出现用户重复而报错,此时这个添加用户的脚本就失去了它的价值,在这种情况下,我们就需要在自动化测试用例的最后加上删除这个用户的步骤,这样在下次执行用例时就不会出现用户重复的情况了。当然,除了回归原点,还可以使用另一种方式进行,那就是初始化数据,比如ATM机取款,假设需要执行取款100元的操作,而银行卡余额是120元,当测试脚本第一次执行时可能没有任何问题,但是第二次系统就会报余额不足,这样就成为了死脚本,解决方案有两种:一种是直接进行初始化数据,每次执行用例之前都重置下余额(只需大于100即可);第二种方法可以在用例执行前,先查询下余额是否大于100,若大于等于则继续,若小于则做一笔充值100的操作,这样即可解决。两种方式可以看具体情况使用,数据初始化方便,但有时候初始化之后可能会影响到其他自动化测试用例的执行,而第二种方式相对在脚本上需要稍微花点功夫。究竟使用哪种方式还需要具体情况具体分析。总之,在执行自动化测试用例之前做好数据准备,这也是自动化测试的关键步骤。

原则5:自动化测试用例和手工测试用例不同,不需要每个步骤都写预期结果。

在手工测试用例的设计过程中,几乎每一个测试步骤都有一个预期结果。但是,在自动化测试用例的设计中并不采用,在自动化测试用例中,只有准备在测试脚本中设置成检查点的步骤才有预期结果,其他所有的步骤只将它看作一个步骤,这样做的好处是一目了然、目的明显、层次分明,以后写测试脚本直接跟着自动化测试用例就行了。因为经过前面的探讨应该已经知道,自动化测试中并不是所有的东西都需要验证的。所以,作者在前面的章节中也提到过,基本上手工测试用例多多少少都要进行一些转换的,就是因为它们之间的格式是不一致的。举一个简单的例子,假设需要设计一个注册页面的自动化测试用例,有10几个表单需要填写,在手工测试用例中,每个表单的填写都一定会有预期结果,因为它的确在检查每一项是对了还是错了,只是用的是你的眼睛在检查而已,所以速度非常的快,甚至你自己潜意识都忽略了其实你已经检查了。但是,在自动化测试中,我们知道如果你要检查,那一定需要写代码,如果每项都检查,那代码量有多大是可想而知的,不是说做不到,只是这样做根本不符合自动化测试的特点。所以,绝大部分时候,这些在自动化测试中可有可无的检查,我们全部“不检查”,只当做一个业务流程和步骤,是不需要设立预期结果的。

 

1.1.4 教父级自动化测试工具QTP

由于测试工程师经常会遇到许多循环重复劳动,非常枯燥乏味,给测试工程师带来了许多不必要的重复任务,因此,为了减少测试从业人员的工作量,自动化测试工具就这样诞生了。

目前,市面上的自动化测试工具有很多,选择面也非常的广,比如目前全球市场占有率最高的QTP,还有SilkTest、WinRunner、Watir、Rational Robot、TestComplete、RFT 等。这些都是目前主流的自动化测试工具,我们再来参考一下 Indeed.com 网站提供的一项从 2005年~2010年的主流自动化测试工具趋势分布图,如图1-2所示。

图1-2

从图1-2中可以分析出,从2005年~2006年左右,WinRunner一直是主流地位,占有率最高,而从2007年开始,QTP慢慢地兴起,开始有超越WinRunner的势头,这段时间Mercury已经停止了WinRunner的版本更新、下载以及服务,而把主要战略方向转投向他们近几年非常成功的QTP。从2007年后半年开始,WinRunner开始走下坡路,而此时QTP和Selenium正以十分迅猛的势头赶超上来。直到今天,QTP 成为了最终的霸主,而Selenium排行老二, WinRunner 只能位居第三,其余自动化测试工具基本没有多大的变化。不过趋势图有些地方还是只能作为参考的,而且这张数据图的出处在国外论坛,不能完全反应国内的一些情况。作者个人感觉目前Web测试中开源的Watir测试框架在全球也有一定的市场占有率。那么接下来我们就来看一下商业化自动化测试工具QTP的实力。这里作者就拿QTP与Watir进行一个简单的对比作为参考,如表1-1所示。

表1-1 QTP和Watir对比
续表

可以看出,在表1-1中,QTP很多功能都是Watir无法比拟的。当然,此表也只是列举了一些表面功能上的对比,QTP还有许多更深层次的功能是其他任何自动化测试工具所无法比拟的。不过呢,任何事物都有两面性,有好的一面也总有不大好的一面,QTP最大的缺点就是价格相当昂贵,而且由于其商业工具的特殊性,所以不可能开源,导致无法对测试工具本身的核心进行个性化的扩展定制。这点Watir就比较好了,虽然有很多功能没有QTP那么强大,但其开源的特性使得我们可以对其进行随意的修改和扩展,可以把需要实现的功能进行二次扩展开发,同样也可以使其成为一款非常强大的自动化测试工具。不过这肯定需要非常强大的编程功底以及一定的开发工作量,需要投入大量的时间和精力。

从下一章开始,本书将对自动化测试工具QTP进行深度的剖析,同时结合大量新鲜实例,使读者能够在实际项目中掌握 QTP 的应用。内容会由基础核心、到高级扩展、到领先技术、再到框架展示,拨洋葱式的层层深入,让读者能够由浅入深地掌握好测试自动化这一门技术。

 

1.1.5 总结

本章节是作者根据其多年的自动化测试项目实战经验和学习经验的一个深度总结。可以使读者绕开弯路,循规蹈矩地认知到底什么是自动化测试,以及其中的一些精髓理论!章节中穿插了大量的实践、实用元素。

 

知识点巩固和举一反三练习

一、请审题后根据题目的素材设计“最最简单的登录功能”的自动化测试用例。

素材1:系统名称<XX自动化测试用例设计练习系统>,B/S架构。

素材2:整个登录功能的验证只涉及2个页面<登录页面>、<内容页面>。

素材3:“登录页面”具备4个控件[用户名输入]、[密码输入]、[登录]、[重置]。

素材4:“内容页面”中存在文字<欢迎回来,xx>,具备1个控件[退出系统]。

素材5:该系统如果不用手工清除IE缓存,不点击[退出系统],直接关闭网页,下次访问无须重新登录,直接以已登录状态访问<内容页面>,非常方便。

素材6:在“素材4”中,内容页面里的文字专门用作检查登录系统是否成功。

二、请根据要求将手工测试用例转化成自动化测试用例。

手工测试用例设计表

要求1:需要验证点击[注册]按钮后是否能够成功进入注册页面。

要求2:“用户昵称”需要在测试脚本中验证字段。

要求3:需要验证注册完毕后系统的反应。

附:自动化测试用例设计表模板参照

 

1.2 帮助文档(HELP)-QTP的说明书

阶段要点

• F1 的简单介绍。

• 焦点功能引导法。

• 脚本定位跟踪法。

• 查阅Example 实例技巧。

 

1.2.1 永远任劳任怨的良师益友“F1”

1.2.1.1 “F1”的简单介绍

F1 键相信很多朋友都不会陌生,举个最简单的例子,当用户打开Windows 自带的notepad (记事本),按下F1键后,系统就会自动弹出notepad的帮助文档,如图1-3所示。

图1-3

不止是notepad有F1,微软Office的Word/Excel/PowerPoint有F1,QQ/MSN有F1,IE有F1,甚至是Windows的桌面也会有F1,不管你使用的是什么软件,F1总是能如影随形的跟着我们,在我们最需要的时候给予最大的帮助。这就是F1,在你刚刚入门时,它会成为你的向导栏;当你处于迷茫时,它会成为你的指路牌;当你准备学习前,它会成为你的教科书;当你需要查询时,它将成为你的小词典。

接下来就来看一下QTP中F1的使用,首先打开QTP,切换到ExpertView后,点击F1,就可以看到QuickTestProfessional Help 文档,如图1-4 所示。

从图1-4中可以看到有4个tab,在第一个tab中可以看到一共有8本书。

Welcome。

大致对QTP做了简单的介绍以及帮助文档的使用与更新。

What’s New in QuickTest Professional。

主要介绍了当前QTP版本的一些新特性。

XHP QuickTest Professional User Guide。

图1-4

QTP的一些基本知识,建议初学者能认真的把这本书通读一遍。

HP QuickTest Professional for Business Process Testing User Guide。

介绍如何使用业务组件功能来进行测试。

HP QuickTest ProfessionalAdd-ins Guide。

对QTP所有支持的插件的使用方法进行了简单介绍。

HP QuickTest Professional Object ModelReference。

用于查阅QTP所有封装对象的接口与用法。

HP QuickTest ProfessionalAdvanced References。

QTP的一些高级用法,需要深入学习的建议读一下。

VBScript Reference。

对QTP的平台语言进行详细的介绍,查阅时也相当有用途。

1.2.1.2 如何获取最新的帮助文档

如果需要获取 QTP 最新版本或者任意版本的帮助文档,可以直接打开 IE,进入 http://h20230.www2.hp.com/selfsolve/manuals (需注册登录)。如图1-3 所示。

Product:

QuickTest Professional。

Product Version:

选择需要的版本。

Operating System:

Windows。

按要求选择产品以及所需要的版本并点击Search按钮后,页面下方即会显示所有文档的列表。左边一栏是标题,右边一栏是文档更新的日期,如图1-6所示。

图1-5
图1-6

 

1.2.2 妙用F1可事半功倍

做任何事情都会有一定的方式方法,好的方式方法可以达到事半功倍的效果,下面我们就来看一下如何才能更好地利用F1键来解决实际中遇到的问题。

1.2.2.1 焦点功能引导

之前说过F1对于新手来说是个非常有利的工具,它可以引导用户熟悉QTP的每项功能。当你的手指按下F1键的瞬间,F1就会被激活并且激活的内容会与当前的焦点自动匹配。这样的一种引导模式对于新手的学习来说,是非常便捷的。

→技术指导:切换焦点后点击F1。

焦点切换到DataTable,如图1-7 所示。

焦点切换到对象库(图1-8)。

图1-7
图1-8

焦点切换到SPY(图1-9)。

图1-9

无论焦点走到哪里,F1都能精确地对内容进行匹配,可以充分利用此功能进行模块化以及针对性的学习。对于已经熟悉QTP的读者,此功能也是非常有帮助的。因为我们不可能把QTP的所有功能都一一吃透,大多数情况都只是对常用的功能比较熟悉,当在项目中遇到了瓶颈需要使用QTP的新功能或者新技术来解决问题的时候,在面对QTP的一些不是很了解或者相对比较陌生的功能时,此时最好的帮助老师就是F1。当然还可以找“百度大叔”。如果是对于每次 QTP 升级版本时的新功能发布而言,“百度大叔”也就束手无策了,最终还是只能靠F1。

1.2.2.2 脚本定位跟踪

刚开始学习使用专家视图的读者一定会非常困惑一个问题,那就是每个QTP的封装对象都会有N多个方法,每个方法都代表着不同的含义,有着不同的用法,在调用方法时还会有不同的参数,不同的参数类型以及是否有返回值等一系列的问题。

→技术指导:双击定位选取后点击F1。

我们来看一段很简单的脚本:

'************Launch IE **********

Systemutil.Run "IEXPLORE.EXE","http://bbs.51testing.com/default.php"

' ************CLOSE BROWSER************

Browser("51Testing软件测试论坛软件测试|").Close

此脚本所实现的功能就是启动 IE,打开 51Testing 论坛后,关闭浏览器。这里的 Close其实就是Browser下的一个方法。这个方法可以实现关闭浏览器。这是一个非常简单的脚本,在Browser对象后输入一个“点”后,QTP会弹出很多的方法,而有些方法对于新手来说不是很了解,可以使用脚本定位跟踪的方法来掌握每个方法的含义和具体用法。

定位对象。

双击选中专家试图中的对象名Browser后,自动选中Browser脚本字符串,F1后页面显示对象的所有方法介绍,如图1-10所示。

图1-10

定位方法。

当需要直接定位对象方法时,可以直接双击选中专家视图中的方法名Close,按F1键后页面显示Close方法的描述、参数个数、返回值等,如图1-11所示。

图1-11

 

1.2.3 请遗忘脑中的代码,掌握查阅Example实例技巧

1.2.3.1 封装方法实例查阅

上一章我们讲了脚本定位跟踪,这一章主要来讲跟踪后查阅Example实例的技巧。在这里再次提醒读者,脚本不是死记硬背的,而是要活学活用的,成千上万个方法也不可能都把它背下来。所以,必须掌握这个技巧来应对下一个未知的方法。还是用上一节的例子查阅一个方法的描述如表1-2所示。

表1-2 方法的描述

学会查阅方法是一种必备的技能,当看到一个陌生的方法时,必须能够会使用定位跟踪方法进行查阅,仔细查看对象的方法描述、语法使用、语法细节、返回类型、举例说明。特别是举例说明这一栏,作者个人感觉是很实用的。有时候一个过于复杂的方法,介绍也写的有些含糊,这时可以点击example实例进行查看能够省去很多的时间。如Close方法,如果没有看懂说明,就可以直接点击example,页面就会显示此方法的具体实例,如图1-12所示。

图1-12

实例程序如下:

Sub Close_Example()

'The following example uses the Close method to close the

'Mercury Tours application.

Browser("Mercury Tours").Page("Search Results").Image("reserveFlights").Click 41, 20

Browser("Mercury Tours").Page("Method of Payment").Image("buyFlights").Click 11, 5

Browser("Mercury Tours").Close

End Sub

当看完此实例后,就能够轻松掌握Close方法的所有用法了。

1.2.3.2 VBScript 方法函数查阅

QTP的底层语言是VBScript,因此是否能够灵活运用好VBScript脚本语言在自动化测试中是至关重要的。VBScript虽然语法不多,也不是很严谨,但是方法和函数却非常繁多,往往新手在学习时都不能把全部的函数和方法都熟记下来,因此必须找出一种方式方法来摆脱这种非常被动的局面。通过F1定位进行实例查询,现学现用。

实例InStr 函数的定位。

首先在QTP里输入Instr,双击选取Instr后,点击F1进行内容定位匹配,接着就可以看到Instr方法的介绍与用法,如图1-13所示。

从帮助文档的说明中可以看到,此函数返回的是一个字符串在另一个字符串中的首个位置,参数一共有4个,如下所示。

图1-13

Start:起始位置,可选。

String1:需要被搜索的字符串,必选。

String2:需要搜索字符串,可选。

Compare:比较方式,可选。

对于新手来说,看完以上这些说明之后,若还是比较迷茫。怎么办呢?可以直接把Example的内容拷贝到QTP中执行一遍,相信一定会恍然大悟的,并且会发现原来这个函数的用法是那么的简单,对自动化测试的学习也会越来越有信心。

InStv实例程序如下:

Dim SearchString, SearchChar, MyPos

SearchString ="XXpXXpXXPXXP" ' String to search in.

SearchChar = "P" ' Search for "P".

MyPos = Instr(4, SearchString, SearchChar, 1)

' A textual comparison starting at position 4. Returns 6.

MyPos = Instr(1, SearchString, SearchChar, 0)

' A binary comparison starting at position 1. Returns 9.

MyPos = Instr(SearchString, SearchChar)

' Comparison is binary by default (last argument is omitted). Returns 9.

MyPos = Instr(1, SearchString, "W")

' A binary comparison starting at position 1. Returns 0 ("W" is not found).

通过Example可以很明显地看出,需要搜索的范围是XXpXXpXXPXXP,而搜索的内容为P,第一个则是在这个搜索范围里从第4个位置开始搜索P,直到找到P位置,然后停止搜索,并返回找到的位置。由于此处的第4个参数是1,为文本比较,是忽视大小写的,因此,此处返回的位置为第6个,所以返回值也就是6,后面3个原理基本也是一样的,读者可以自行尝试琢磨一下看。

通过以上的例子相信读者应该已经学会了,如果通过灵活地运用F1来定位内容并匹配,能够现学现用。此技巧不管是对于新手来说,还是已经能够熟练运用QTP的来说都是必备的技能。一旦能够做好了这一点,就相当于把整个 F1 文档都搬到了自己的大脑里、相当于上升到了一个新的台阶。

 

1.2.4 总结

这一章节主要介绍了F1的使用,以及如何通过F1来提高学习与工作的效率,以便掌握现学现用解决实际问题的技巧。虽然这一章的内容较为简单,但是这一章的一些技巧基本会贯穿整个自动化测试学习的过程。需要掌握的是定位跟踪的查阅技巧,而不是去背F1。这才是作者要讲这章节内容的关键所在。希望读者能够牢记并灵活应用。

 

知识点巩固和举一反三练习

1.请利用F1查阅SystemUtil对象的具体用法。

2.请根据以下代码利用F1脚本跟踪定位法来查阅filter方法在如下代码中的用法。

Dim arrIndex

Dim arr (3)

arr(0) = "Quick"

arr(1) = "Quick Test"

arr(2) = "Quick Test Professional"

arrIndex = Filter(arr, "Test") ' MyIndex(0) contains "Monday".

MsgBox arrIndex(0)

 

1.3 录制与回放——QTP的开关

阶段要点

• 录制在实际项目应用中的价值观(极低)。

• 新手切记不可在项目应用时被禁锢在录制中。

• 录制及其相关功能的重点知识点提炼。

• 录制功能“旁门左道”式的妙用。

• 录制的3种模式及应用。

• QTP 回放机制重要原理。

• 实际项目应用时关于QTP 脚本回放的几项重要设置详解。

 

1.3.1 请拒绝“录制”,再开始你的实际项目之旅

1.3.1.1 引言

当人们一提到QTP,第一反应就是,它是Mercury公司旗下的一款强大的商业化自动化测试工具(现已被HP公司收购)。那么当提到QTP有什么主要功能的时候,大家的第一反应一定是“录制”。

很多新人认为,QTP 自动化测试工具最强大的功能就是“录制”。在众多的自动化测试工具中,QTP的“录制”的确做地非常有优势和全面、以及高档。但是,作者很负责任地告诉读者,QTP的录制功能虽然相当精彩,一些相关的“出彩”功能,作者甚至碰都没有碰过,不过这并不影响作者使用QTP出色地完成各类自动化测试项目,因为靠“录制”是做不了项目的,甚至连一个demo都做不出来。

就像作者在之前的“1.1.2 严格的自动化测试流程”章节中说过的那样,自动化测试项目和软件开发项目同属软件工程学,两者是同属一派的。在自动化测试项目的实际应用中,只有直接编码才能出色地根据之前的设计思想来完成脚本,如果是靠“录制+加强”的模式,那就不可能按照前面定制的设计方法和思想来开发测试脚本。

1.3.1.2 一些“理论性的社会实际问题”实例

作者在1.1.2.1“测试流程是关键”这一节中的第五大点里提到过几种测试脚本种类,录制就属于其中最低级的“线性脚本”的范畴。录制出来的脚本给作者这样一种感觉“貌似华丽,其实没有任何价值和思想”,也可以把这类脚本比作古代战场中的一员有勇无谋的武将,表面上凶猛无比,其实只不过是横冲直撞之辈尔,没有任何战略、谋略,必然无法永远打胜仗。

虽然QTP 在录制时有很多“华丽”的辅助功能,比如Keyword View界面的各种直观操作、Active Screen等。但是这些东西基本上也只是有一个华丽的表面而已,如Active Screen,如果开启了这个功能,那么即使你录制一个简单的注册功能,这个脚本的大小估计都有10MB左右!因为脚本里都是截取下来的图!一个注册脚本就要10MB,那么一个自动化测试项目测试下来需要多少MB?另外,在添加对象方面上,录制也显得差强人意,因为靠录制的方式添加对象,表面上来看十分快速,但是通过这种方式添加到对象库中的对象,它们的命名都是 QTP 自动命名的,相当乱,还需要一个个去改,而且很多对象还是不需要的,QTP也给自动添加进来了,这样,效率远不如一开始就一个个添加对象,并根据规范为它们逐一命名再进行编程呢。对象库这章还没讲到,届时会在章节中引导读者做一个有趣的实验来证明,在这里也不再阐述了。

小提示

关于文中提到的“录制”两字。——作者在文中提到的“录制”是指以录制的方式并配合使用其他QTP自带的功能录制出来的脚本,从而完成自动化测试脚本编写的整个过程(线性脚本、结构化脚本都在此范畴之内),而不是指单一的录制功能。举个例子,比如QTP这个测试工具自带了很多检查点的设置与操作,其实在真正的项目应用中,是用不到的,而是靠代码的方式去实现,绝非靠工具本身提供的功能去实现。关于检查点,在这里点到为止,后续的“验证点”章节中,会详细地讲解靠代码实现验证点并且通过实例证明,为什么实际项目应用中的验证是从来不靠QTP自带的检查点功能的。

最后,有一点需要做声明,本书的作者绝对没有诋毁QTP的录制功能,正是因为有了这项强大功能的开发与研究成果,才能让自动化测试工具一步一步走上更高的高度。只是作者觉得,“录制”在实际的自动化测试项目的应用中几乎没有任何可发挥的余地。因为本书并不是一本自动化测试工具功能的介绍书籍,而是一本融合实战技术、项目实践及经验的指导书籍。

在下一个章节中,会对“QTP录制”的核心做必要的介绍和讲解,这些内容,读者还是必须掌握的。

 

1.3.2 录制功能更多的只是新人学习时的利器

1.3.2.1 录制相关功能只需把握几个重点

学习“录制”只是能更多的了解QTP这个自动化测试工具,但在自动化测试项目中几乎没有发挥的余地。如果只从实际项目角度出发,那是不是可以完全抛弃学习呢?是可以的。不过在本章节中,作者总结了一些关于“录制”方面的重点知识点,这些重要的知识点不仅和“录制”有关,它们和以后在具体的项目应用中也有关系。所以把这些知识拎出来作重点介绍。希望可以给读者以启发,本书也从本章节开始正式引领读者去实践QTP、实践自动化测试项目应用。

1.Add-in Manager & BHO Manager

Add-in 和 BHO 相关的知识点表面看似和“录制”没直接联系,其实它不仅仅和“录制”有关联性,和很多知识点也同样都有关联,比如以后会介绍的对象库,可以说这两个一直伴随着QTP自动化测试项目。选择将这两个知识点放在“录制”这章节介绍更加妥当,毕竟无论是“录制”、“插件”、还是“BHO”都是学习QTP一开始就要接触的知识点。

在打开QTP之后,可以看到一个Add-in Manager框(见图1-14)弹出来,这是一个QTP插件管理器,每次启动前需要选择对应的插件(在插件名称左侧打钩)才能进行测试。QTP默认自带3个插件,分别是ActiveX、Visual Basic以及Web,其中属Web插件最重要,使用率最高,也是本书所用到的重点插件。如果需要使用其他插件,可以向官方购买,或由用户自主定制自己的插件。加载新插件后,插件管理页面中就会显示新加载的QTP插件。

图1-14

经常会在测试论坛上看到一些测试同行问“这个项目是用什么语言写的?应该选择哪个插件做自动化测试?”。其实提出这个问题足以证明大家并没有了解插件的真正含义和作用。

插件的含义与作用。

Add-in的选择是为了能够成功识别对应插件的测试对象控件,也就是说插件的选择是和被测对象控件有关的,以QTP应用最广泛的Web网页测试而言,它与项目具体使用的是哪种语言没有多大关系。但是对于Windows桌面应用程序而言,插件的选择是和开发语言有关系的。针对C++、Java和.NET程序,QTP都有相应的Add-in提供,分别用于对应的语言开发的Windows桌面应用程序。

一个实例:

需求:使用QTP的Spy识别“51Testing软件测试网”首页上的[登录]按钮(WebButton)控件,如图1-15所示。

注1:Spy功能是QTP 重要的一个机制,在后续的章节“Object Spy”中会进行详解。这里,只给出该功能的位置及基本用法。

注2:Spy的位置:进入QTP→上方菜单栏→Tools→Object Spy→点击后弹出Spy框。

注3:Spy的基本用法:点击后会出现一个“手指头”并重新切换到之前的页面,用“手指头”点击被测对象控件即可。

图1-15

“51Testing软件测试网”是一个B/S架构的Web网站,需要加载Web插件(见图1-14中的插件选择状况)才能够正确识别网站中的对象。下面看一下选择了正确的插件后,利用Spy定位“登录”这个WebButton对象控件的结果,如图1-16所示。

图1-16

通过图1-16,可以很清楚地看到控件识别成功了。“登录”这个对象控件的所有属性尽在Spy的掌握中。

那么如果没有选择相对应的插件去进行识别会是什么情况呢?首先如图1-17所示,作者把Web插件的钩选去除,只选择Visual Basic 插件。然后再次用Spy 去定位“登录”这个控件。

操作完毕,结果如图1-18所示。

这就是选择错误插件后,Spy的识别图。由于没有选择对应的插件,“小手指”都没有办法具体定位到“登录”按钮这个WebButton控件对象,只能把整个浏览器识别为一个对象。

通过上述内容,相信读者已经对插件有了深刻的了解。但是内容还没有结束,你知道吗?即使选择正确的插件,有时仍然会出现图1-18中的情况。如果以后发生类似的问题,解决办法相当简单,只要关闭 QTP 和测试网页,然后先打开 QTP,再打开测试网页即可解决!为什么会这样呢?说的简单点就是,QTP和BHO机制是挂钩的。因为安装完QTP之后,每次打开IE,浏览器会自动加载BHOManager,而QTP在IE中识别对象是依靠一个名为BHOManager Class 的动态链接库来完成的,如果是先打开IE 再打开QTP,QTP 就不能成功读到BHOManager Class 这个动态链接库,从而导致QTP 识别对象失败。

图1-17
图1-18

小提示

What is "BHO"?——BHO(Browser Helper Object,浏览器辅助对象,简称BHO)。BHO是微软推出的作为浏览器对第三方程序员开放交互接口的业界标准,通过简单的代码就可以进入浏览器领域的“交互接口”(INTERACTIVED Interface)。BHO对象依托于浏览器主窗口。实际上,这意味着一旦一个浏览器窗口产生,一个新的BHO对象实例就要生成。任何BHO对象与浏览器实例的生命周期是一致的。其次,BHO仅存在于Internet Explorer4.0及以后版本中。BHO是一个COM进程内服务,注册于注册表中某一键下。在启动时,Internet Explorer查询那个键并把该键下的所有对象预以加载。

所以,请每位读者要特别注意这里的小细节,别疏忽了它。

2.Record and Run Settings

它翻译后的中文是:录制与运行设置。即和录制有关系又和运行有关系,它们和“Add-in”及“BHO”一样,同样会一直伴随着QTP自动化测试项目。

这个知识点从界面就可以很直观地了解了,先看以下两张图(图1-19、图1-20)。

图1-19
图1-20

注1:Record and Run Settings的位置:进入QTP→上方菜单栏→Automation→Record and Run Settings。

点击Record and Run Settings 后,会弹出一个窗口,窗口中有两个选项卡,分别是Web选项卡(图1-19)以及Windows Applications 选项卡(图1-20)。

先介绍最常用的Web选项卡,它用在B/S架构的系统中。作者已经在图1-19中对每个选项进行了编号,让我们对Web选项卡下的各选项进行全面的了解。

(1)Record and run test on any open browser。在任意打开的浏览器上录制和运行测试组件。

选中这个选项后,在录制的时候,这个选项需要手动打开浏览器,并且在录制的过程中可以随时暂停录制、修改、继续录制等。在回放的时候选择了这个选项就会引申出一个问题了。

举一个实例,假设当前计算机上同时开启了两个网页A和B,录制的脚本是网页A的,大家都知道网页只能同时看一个,如果此时网页定格在网页B(也就是说你在看网页B),你重新回到QTP并点击“F5”运行脚本,此时QTP其实是在网页B上运行脚本的,而脚本里的各个元素又是针对网页 A 的,然后理所当然 QTP 就会一直卡在那里不动直到等待时间超过后报错,原因很简单,QTP无法识别网页B上的控件。所以,读者以后千万要避免类似的问题发生,解决办法也很简单,最好是在做自动化测试运行工作时只开启一个网页,如果一定要开启多个网页,也请记得在运行前把网页重新激活定格到被测试网页中。

(2)Open the following address when arecord on run session begins。当开始录制时打开下面输入的地址。

选中这个选项后,会同时激活网址输入框及图中的“3”、“4”、“5”,在网址输入框中输入需要的被测网页地址即可,此时QTP就会打开该网页。

(3)Open the following browser when a run session begins。当开始录制时以下面选择的浏览器类型打开。

在选中了图中的“2”后被激活,以下拉框形式选择浏览器类型,默认只有1个浏览器类型:Microsoft Internet Explorer。

(4)Do not record and run on browsers that are already open。在已经打开的浏览器上不录制和运行脚本。

在选中了图中的“2”后被激活,可选项,默认打钩,含义如上。

(5)Close the browser when the test closes。在测试组件关闭后同时关闭浏览器。

在选中了图中的“2”后被激活,可选项,默认打钩,含义如上。

小提示

在Web选项卡中最主要的选择就是Record and run test on any open browser 和Open the following address when a record on run session begins了。后者自动打开浏览器,一般在初始录制的情况下使用。同时,自动打开浏览器也是为初级用户提供的,完全是为了配合“录制”这个功能而开发的。手工写脚本的情况下,一定是选择前者。在这里先预告下,在QTP脚本开发中,打开浏览器的函数是SystemUtil,在后续的章节中会详细讲解该函数,这个函数下的很多方法在实际项目应用中都相当实用。

(5)Applications specified below。在下方Applications details里指定程序路径。

接下来介绍Windows Applications 选项卡,这个选项卡是关于QTP 在录制应用程序时的应用设置。作者已经在图1-20 中对每个选项进行了编号,下面对Windows Applications 选项卡下的各选项进行全面的了解。

(1)Record and run test on any open Windows-based application。在任意打开的Windows底层程序上录制和运行测试组件。

原理和Web一致,不再重复阐述。

(2)Record and run only on。只在XX 应用程序上录制和运行。

选中这个选项后会同时激活图中的“3”、“4”、“5”、“6”。

(3)Applications opened by Quick Test。被QTP 打开的应用程序。

在选择了图中的“2”后被激活,可选项,默认打钩。在这里要说明一下,被QTP打开的应用程序可以是由“6”中手工添加程序的方式也可以是由代码的方式,代码函数仍然是SystemUtil。

(4)Applications opened via the Desktop (by the Windows shell)。通过快捷方式或快速启动栏打开的程序(包括开启录制之前、之后打开的)。

在选择了图中的“2”后被激活,可选项,默认不打勾。这里要注意一下,如果决定勾选这个选项,一定要勾选“5”(为什么一定要勾选“5”会在下面讲到),然后添加快捷方式或快速启动栏图标的实际路径。

在选择了图中的“2”后被激活,可选项,默认打钩。如果不打勾,则不会激活“6”,也就无法添加程序。在“4”里讲到必须勾选“5”就是因为这个原因,只有勾选了才能在下面的Application details space里添加程序实际路径、快捷方式实际路径或快速启动栏图标实际路径等。

(6)Applications details space。程序详情资料空间(space 是作者自己加的)。

在选中图中的“2”并勾选“5”后被激活。这个区域被激活以后有新增、编辑、删除 3个按钮,并且在添加程序完毕后以列表形式显示并排列,如图1-21所示。

下面看一下如何添加程序,点击添加按钮(绿色的+号)后的效果,如图1-22所示。

图1-21
图1-22

在点击添加按钮以后就会弹出图1-22中的界面。

Application:这里是添加程序具体路径的地方,可以手动输入,也可以通过右侧路径按钮进行选择。需要注意的是,这里的路径是需要定位到文件名的,比如 flight4.exe,如果是QQ的话,就是QQ.exe。

Working folder:这里是添加工作文件夹的路径,不用具体定位到文件名。

Program arguments:简单的说就是输入一个程序变量的编辑框,平时就算是“录制”。

Launch application:可选项,默认勾选,勾选后的效果是,在录制的时候可以自动开启程序。

Include descendant processes:可选项,默认勾选,对于实际项目的应用同样做不了贡献,如果读者感兴趣,可以使用第2小章节中讲到的F1定位跟踪技术自行研究。

3.Web Event Recording Configuration

首先,公布下这个功能的入口处:进入QTP→上方菜单栏→Tools→Web Event Recording Configuration,点击进入后会出现如图1-23所示的界面:

该功能只能应用于B/S架构的系统,在录制时,对一些Web事件进行设置,这个设置究竟是怎么回事?设置后的效果是什么?稍后,作者会举一个例子,然后在 51Testing 网站上选择一个相对比较贴切的实际场景进行操作,让读者看明白。

图1-23

先熟悉一下这个弹出的界面,首先了解一下Event configuration level 的概念,QTP 把它默认分成3级:Basic(最下面那格,也是默认的设置,图1-23的显示效果就是Basic效果)、Medium(中间那格)、High(最上面那格),要设置等级只需要将游标移动到相应位置即可。其次,可以看到有Custom Settings按钮,这个按钮就是用户的个性化定制,在QTP默认的3 个等级都不符合场景需求时,可以使用该功能(下文会对这个功能的要点作讲解)。最后,Default Settings 是恢复QTP默认设置功能。

对这个界面了解后,作者开始举第一个例子,事先提醒一下,现在的Eventlevel 是QTP默认的Basic等级(选了等级后,等级名称下会有些该等级的介绍,读者可以自行查看),大家设想这样一个场景(相信大家在项目中应该也碰到过类似的场景):有一个在线学习考试系统,在购买课程页面上显示了很多课程信息(如价格、有效期等),然后每个课程都有一个备注功能,要查看备注内容则需要将鼠标光标移上去并保持2秒钟后,会以popup形式弹出备注框后才能查看到。好了,有了这么个需求,那现在需要用QTP验证这个备注框的内容是否符合预期结果。首先肯定要做到的就是使其popup,手工操做是很简单的,放上去等2秒就好了,但是用QTP不一样,在Basic等级下,QTP在录制时是无法模拟到“放上去等 2 秒的操作的”。解决的办法就是需要把 Event level 提高到可以模拟这个操作的那个level。只有通过该解决方案才能解决项目应用的实际问题,不然这个自动化测试用例就没法实现成脚本!接下来,就从51Testing网站挑选一个相对比较适宜的场景,录一段脚本,一起来看看脚本效果。在这里先知会一下,作者找了很久,实在没找到51Testing网站上有popup形式的控件,所以,作者的实例不是以popup形式的,不过原理是一样的,而且还可以多了解不同的场景。先看看场景图1-35所示。

图1-24中作者用到的场景区域进行了标示,简单介绍一下,这块区域是一个信息公告区,不是静态的,是动态地从下到上滚动显示的。然后当将鼠标光标移动到某条信息上时,整个信息公告区就会变成静态的了,点击后就可以查看到那条信息。现在提出需求:成功将鼠标光标移动到[企业内训]下的第2条信息“圆满完成上海西门子医疗器械有限公...”上面,等待0.5秒,待信息公告区移动禁止后点击,这个需求很简单,(注:这里强调一下,等待0.5秒的需求是作者虚拟出来的,实际上鼠标光标只要放到信息公告栏里,信息就会变成静态的)。

现在开始分析,从手工操作的角度上来说,完成这个业务需求的时间不会大于2秒。步骤就是,鼠标光标→移动到信息上→等待信息公告区从动态变成静态→点击。但是从用QTP角度上来分析,就不会像手工操作那么简单了,难点就和popup例子一样,如何能使QTP模拟到鼠标光标停止在第2 条信息上0.5 秒的操作。其实就是将Event level 提高或自定义至可以完成这个需求。Basic这个默认的等级完成不了这个需求,调高2级至High这个等级就可以了,反正这个实例只是为了给读者看看实际效果,原理之前就已经讲述了。大家只要知道,项目中遇到搞不定的需求只要把等级提高就行,如果 QTP 默认设定的几个等级都无法满足项目中的需求那就进行个性化定制(这方面有些重点内容等后面会讲解),即可完美搞定!实现的效果如图1-25所示。

图1-24
图1-25

我们可以看到,用Basic等级录制出来的脚本根本无法实现鼠标光标停留在第2条信息上的需求,尽管在录制的时候鼠标光标是停留了0.5秒后再点击的,但是QTP无法录制到。但是用High等级就不同了,鼠标光标停留的动作就被录制到了,函数是FireEvent,参数是onmouseover,它就是传说中的“鼠标悬停”事件。预告下,在下面的“1.3.4小节”中会讲关于FireEvent函数结合该节内容做一个实例演示,这个函数事件的知识点还是比较常用的,敬请期待吧!

好了,现在讲一下如果用High等级都满足不了需求的情况下,就需要个性化定制了,点击Custom Settings 按钮后进入如图1-26 所示的界面。

图1-26所示左边是QTP的对象列表树,包含了Web中QTP所能识别的所有控件,可以通过Add Object 添加Object 控件。右边是与控件相对应的实例,包含了相对应的控件的鼠标光标录制属性,可以通过Add Event 来添加Event 类型,点击OK 保存设置。个性化定制完毕后就可以开始录制脚本了。

图1-26

4.脚本录制的一些良好建议和注意事项

上文中的1、2、3都是读者必须了解,并在项目实际应用中使用价值比较高的“录制”方面的知识点。最后,作者对“录制”进行总结,并根据实际经验给出一些意见。

在开始录制之前,应关闭录制会话不需要的所有浏览器、网页或应用程序,以免造成不必要的困扰,从而影响工作效率。

如果在网站上进行录制,应确定该网站的安全区域。当在Web浏览器中录制时,浏览器可能用安全警告对话框提醒,这样在脚本运行时就会由于对象库中没有事先添加安全警告对话框这个对象而导致脚本运行失败。解决方案有两个:一是选择禁用/启用这些对话框,二是将安全警告对话框添加进对象库。

事先明确好准备在录制和运行测试时,如何打开Web 浏览器或应用程序。可以选择让QTP打开一个或多个指定的Web浏览器或应用程序,也可以在已经打开的Web浏览器或应用程序上录制和运行,但是务必事先明确,以免发生不必要的“意外”。

如果要对Web对象进行录制,必须对该对象的值进行更改或初始化还原,以便使QTP录制到该步骤。例如,要录制WebList对象的选择操作,如果页面上已经选择过某选项了,就必须单击该下拉列表,滚动到最初的那个默认选项(当然,这一步可别录进去啊!),然后再重新选择你准备选择的备选项(这叫还原)。如果不还原,可能会导致脚本在运行时无法通过。

1.3.2.2 为什么说录制是学习利器,有根有据,请听我细细道来

作者一直认为学习“录制”相关方面的知识绝大数时候不是为了今后能在实际项目中应用,而是能对QTP做一个整体的了解,包括QTP的一些原理、QTP的一些主要功能、用QTP进行自动化测试的基本业务操作流程等。可以这么说吧,“录制”只能说是用QTP做自动化测试项目的“启蒙老师”,有将“徒弟”引进门的功劳,但最多也就这点功劳了,因为做实际项目“录制”是不够用的,以后必须进行不断深造。

作者在这里还要给大家分享一个小小的经验和技巧。录制这个单项且独立的功能,在以后具体做项目写脚本的过程中是有辅助作用的,也可以说是小小的“投机取巧”吧。在前面的章节中就有这么一个理念,那就是“要以代码的方式写脚本,但不要硬记代码,有问题用F1查找”!首先,作者保证这个理念肯定是正确的,但是,有时候会遇到这么一个窘境,先让我们看图1-28所示。

图1-27

对[同意网站服务条款]这个WebCheckBox控件“打钩”或者“取消打钩”的代码分别是:

'勾选[同意]的代码如下:

Browser("51Testing软件测试论坛软件测试|").Page("51Testing软件测试论坛软件测试|").WebCheckBox("同意").Set "ON"

'取消勾选[同意]的代码如下:

Browser("51Testing软件测试论坛软件测试|").Page("51Testing软件测试论坛软件测试|").WebCheckBox("同意").Set "OFF"

很明显,需要“打钩”的话Set方法后面跟参数“ON”;如果需要“取消打钩”,Set方法后面跟参数“OFF”。在手写代码时,这个很好记住,参数ON 是打钩、参数 OFF 是取消打钩。但是,参数后面的“ON”或者“OFF”是大小写就没那么好记了,经常容易忘记或混淆!如果在该写成大写的时候误写成小写,那么就相当于参数写错,最后运行脚本肯定是过不了!如果你有经验,能反应过来是大小写问题;如果没经验,估计需要折腾一阵子,说不定还发现不了到底是哪里出错了,象遇到类似的问题有什么办法应对呢?建议读者在以后的项目测试过程中,可以参考下面的小技巧。

小技巧

如果遇到上述的情况,录制功能就可以帮上大忙了,录制下这个控件的操作,正确的代码就会显示在QTP中!录制出来的代码是不会出错的!

OK,这就是作者在做项目中的一些经验,在这里分享给读者,通过这个小技巧就可以在具体的脚本编写过程中无往不利!

俗话说,打铁要趁热!接下来再一起看第二个实例,先看一下图1-28所示。

图1-28是51Testing论坛的一个搜索功能,可以看到页面中有一个WebRadioGroup控件,这个控件内一共存在4个选项(所有选项都同属于一个控件)。默认选中的是第1个选项“帖子”,假设需求要求将所有选项从左到右全部点击一遍,从第 2 个选项开始点起,点完第 4个选项以后再点击第1个选项。应该说,完成这个需求很简单,请看下面的代码:

图1-28

'预告:作者强烈推荐在脚本的编写过程中尽量多使用With函数,益处良多,在以后的章节

'中会进行介绍,并且在本书中,With的使用率将会非常高!

With Browser("51Testing软件测试论坛软件测试|")._

Page("51Testing软件测试论坛软件测试|")

.WebRadioGroup("st").Select "#1"  '选中“商品”按钮

.WebRadioGroup("st").Select "#2"  '选中”奇虎全文“按钮

.WebRadioGroup("st").Select "#3"  '选中“分类信息”按钮

.WebRadioGroup("st").Select "#0"  '选中“帖子”按钮

End With

在写脚本的时候,WebRadioGroup控件下的选项可以简写,如“#0”等,可以说提供了相当大的方便。但是,新手往往由于不熟悉这些数字的规律,所以不敢乱用简写,在这种吃不准但又想使用简写,且不想花太多时间去研究的情况下,上面的“小技巧”又可以帮助我们达成目标并提高效率,只要简单的录制一下,QTP就会准确、快速地获得这些选项的编号。

 

1.3.3 录制时需注意模式的切换

1.3.3.1 3 种录制模式的基本介绍

在这一小节中,将要介绍QTP中的3种录制模式:正常录制、模拟录制、低级录制。

1.正常录制模式

QTP 默认的录制模式,这种录制模式是 QTP 最突出的特点,是直接对对象的操作,可以说此类模式继承了对象模型的所有优点,能够充分发挥对象库的威力。它通过识别程序中的对象来代替以前依赖识别屏幕坐标的形式。但是正常模式并不能保证识别程序中所有的对象,因此,仍然需要其他两种模式来补充。在录制完之后,不管再次打开的对象位置在哪(简单的说就是不具体记录对象控件的坐标,但是被测页面上必须存在该控件对象),它都能执行到。开启正常录制模式的方式。

(1)QTP上方菜单栏→Automation→Record。

(2)直接使用快捷键“F3”。

(3)在QTP界面上点击正常录制图标,如图1-29所示。

图1-29

2.模拟录制模式(Analog Recording)

此类模式录制了所有键盘和鼠标的精确操作,对于正常录制模式不能录制到的动作,可以使用模拟录制模式来弥补。例如,录制一个鼠标光标拖动的动作,正常录制模式无法录制这个业务操作,这时就可以考虑切换到模拟录制模式记录鼠标光标的轨迹。模拟录制模式录制下来的脚本文件比较大,而且依靠这种方式是不可以由QTP进行编辑的。选择模拟录制模式,如果在回放时,改变了屏幕的分辨率或者窗口/屏幕的位置, 回放就会失败。开启模拟录制模式的方式。

(1)前提是开启正常录制模式。

(2)QTP 上方菜单栏→Automation→Analog recording。

(3)直接使用快捷键“Shift+Alt+F3”。

(4)在QTP界面上点击模拟录制图标,如图1-30所示。

3.低级录制模式(LowLevel Recording)

此类模式是用来录制 QTP 不能识别的环境或对象。它不止录制了鼠标和键盘的所有操作,对对象的位置要求也非常严格。按此模式录制的对象都以Windows和WinObject的形式存在。QTP按照屏幕上的x坐标和y坐标录制该对象,将所有父类对象录制为Windows测试对象,将所有的其他对象录制为 WinObject 测试对象。它们在 ActiveScreen 中显示为标准Windows对象,并且在录制回放时,对象的坐标有任何一点改变就会失败。这类方式适用于QTP 不能正常识别对象时的应用,主要是记录坐标的位置,可以对 QTP 不支持的对象进行坐标记录。但是不到万不得已的时候,不推荐使用此模式。开启低级录制模式的方式。

(1)前提是开启正常录制模式。

(2)QTP 上方菜单栏→Automation→LowLevel Recording。

(3)直接使用快捷键“Ctrl+Shift+F3”。

(4)在QTP界面上点击低级录制图标,如图1-31所示。

图1-30
图1-31

以上就是QTP的3种录制模式,读者可在进行录制时,根据实际的业务需求进行灵活地切换运用。只有在正常模式下不能录制自己想要的业务操作的时侯才可以使用模拟录制和低级录制,模拟录制和低级录制比正常录制需要占用更多的硬盘资源。一般先使用正常录制模式录制脚本,碰到正常模式不能录制到的脚本时再切换到模拟录制或低级录制来录制这些步骤,之后别忘记再切换回来。

实际上,遇到正常模式下无法录制的解决办法还有很多,比如在上一个小章节中提及的Web Event Recording Configuration 实现一些鼠标事件,诸如onmouseover事件等。

1.3.3.2 Analog Recording 和Low Level Recording 的区别与规则

在1.3.3.1小节中,介绍了模拟录制模式和低级录制模式,细心的读者可以发现,这2个录制模式之间有很多的相似之处,容易产生混淆。其实,它们之间无论在功能还是实际用法上都有很大的区别。

1.Analog Recording(模拟录制)

将“模拟录制”应用于要在录制期间录制鼠标光标的实际移动的应用程序。这些可能包括绘制鼠标签名或者使用通过拖曳鼠标光标创建图像的绘图应用程序等。

模拟录制模式分为两种:一种是相对于指定窗口的录制,另一种是相对于屏幕的录制。

相对于指定窗口录制。选择相对于指定窗口录制,就会只录制鼠标、键盘的指定窗口内的所有动作,而不会录制在指定窗口外部执行的任何单击或鼠标光标移动。当使用这种模式时,QTP 不会捕获任何Active Screen 图像。

相对于屏幕录制。可以录制在整个屏幕内所做的所有动作,包括点击Windows 任务栏上的QTP图标,但在QTP窗口内所做的操作不会进行录制。当使用这种模式时,QTP将捕获你在其中进行录制的窗口的最终状态的Active Screen 图像。

使用“模拟录制”录制的步骤被保存在单独的数据文件中。该文件与在其中录制模拟步骤的操作或组件一起存储,并且在以“模拟录制”模式进行录制时,QTP将向测试或组件添加一个调用所录制的模拟文件的“RunAnalog”语句。相应的Active Screen 将显示在模拟录制会话期间执行的最后一个模拟步骤的结果。

2.Low Level Recording(低级录制)

将“低级录制”应用于在不受QTP支持的环境或对象上进行录制应用程序。或者当需要在应用程序屏幕上录制操作的精确位置时,也请使用“低级录制”。

当以正常模式录制时,不用关心对象控件具体在什么位置,即使该对象控件每次都移动到屏幕上的新位置也没关系。但是,如果对象控件的位置方位对于测试或组件非常重要,请切换到“低级录制”以使QTP能够按照屏幕上的x坐标和y坐标录制该对象。这样,在运行脚本的时候,该步骤只有在对象控件位于正确的位置时才能通过。

前一个小节中提到过,当使用“低级录制”时,QTP 将所有父类对象录制为 Windows测试对象,将所有其他对象录制为WinObject 测试对象。它们在Active Screen 中显示为标准Windows对象。下面列举“低级录制”对每个测试对象支持的方法。

WinObject测试对象:Click、DblClick、Drag、Drop、Type 。

Windows 测试对象:Click、DblClick、Drag、Drop、Type、Activate、Minimize、Restore、Maximize 。

以“低级录制”模式录制的每个步骤都显示在关键字视图和专家视图中,而“模拟录制”仅仅录制关键字视图中那个调用外部模拟数据文件的步骤。

总结。当选择“模拟录制”或“低级录制”时,需要参考一定的规则性,才能做到事半功倍的效果,在遇到实际问题时仔细考虑以下规则。

只有当QTP的正常录制模式不能准确录制和满足业务操作时,方可使用“模拟录制”或“低级录制”。

“模拟录制”和“低级录制”要求比正常录制模式更多的磁盘空间。

对于特定的业务步骤,可以在录制会话期间切换到“模拟录制”或“低级录制”。在以“模拟录制”或“低级录制”模式录制了必要的业务步骤之后,就可以返回到正常录制模式来完成录制会话的其余部分。

 

1.3.4 有必要让你掌握尤其重要的QTP回放机制

掌握了QTP录制的原理那就一定要掌握QTP的回放原理,后者的重要性远远胜于前者,因为在做实际项目的时候可以抛弃录制,但是脚本回放永远抛弃不了!QTP的脚本回放机制勤勤恳恳地服务于每一次自动化测试,如果失去它,自动化测试将不复存在!

那么QTP的回放机制大致是一个怎么样的概念呢?最简单的说法就是“回放机制是封装对象与真实对象的匹配”。

深化点讲就是,QTP根据脚本中记录下来的对象操作的顺序进行回放(再通俗点的说法就是,在没有特殊情况下是从上到下执行,一句一句执行的,特殊情况就是,比如遇到Function时会“跳”)。QTP从脚本中读取到该对象,并根据对象的层次和名称到对象库中寻找相同名称的测试对象,在对象库找到相应的测试对象并获得该测试对象的属性,然后根据这个测试对象的属性,在运行的网页或应用程序中进行匹配,寻找运行时对象。如果成功匹配上,再根据脚本中记录的该对象的方法、动作和参数值进行应用,如果未能匹配上,则在超出了等待时间后报错,脚本即宣布运行失败。

在这里公布一下QTP的回放功能怎么开启。

(1)QTP上方菜单栏→Automation→Run。

(2)直接使用快捷键“F5”。

(3)在QTP界面上点击Run图标,如图1-32所示。

了解了QTP回放机制的原理后,下面一起来掌握一些关于QTP回放机制的重要相关设置,并做一些深入扩展。作者总结和提炼了4个相对比较重要的设置,这些知识点在以后的实际项目应用中也经常会使用到。

1.File→Settings→Run

顺利进入设置页面后可以对运行相关方面进行各类不同的设置,页面效果如图 1-33 所示,这个页面下的所有设置在项目应用中都非常重要,下面对这些设置进行分解。

图1-32
图1-33

(1)Data Table iterations.QTP自带的数据表功能在运行时的迭代设置,如图1-34所示。

图1-34 中一共有3 行数据,QTP 默认选中的是Run on all rows 选项,这种情况下,在运行时,QTP则会根据行数来决定迭代运行多少次,如果有3行数据则运行3次。这里要注意一个情况,如果图1-34中有第4行数据,但是数据的值是空,则QTP会运行4次,只是参数的值是空值。

图1-34

如果激活Run one iteration only 选项,QTP在运行时只运行第1行数据,无论后面还存在多少行数据,它只执行第1行的数据且只运行1次。

最后,如果激活Run from row XX to XX选项(假设是3~5),QTP则读取第3~5行的数据并运行3次,从第3行开始执行直到第5行结束。

(2)When error occurs during run session:当在运行期间发生错误时。

pop up message box (默认)QTP 弹出一个错误信息提示框,并显示对应错误。必须去掉这个 错误提示框后才能继续运行脚本。

proceed to next action iteration 继续执行下一个业务行为迭代。举个例子,QTP 自带数据表中有2行数据,当前执行的是第1行数据(即第一次迭代),运行期间遇到错误后,如果此时激活的是这个选项,那么QTP将直接跳过本次迭代,进入第二次迭代(执行第2行数据),如果第二次迭代又发生了错误,此时由于数据表中并没有第3行数据也就没有了后续的迭代操作,所以脚本运行结束。

stop run 这个相当直观,当发生错误,则停止脚本运行。

proceed to next Step当发生错误时,跳过本业务步骤,进入下一个业务步骤,即脚本代码的下一行。

(3)Object synchronization timeout:XX seconds. 同步的延时时长(默认20 秒)。

(4)Disable Smart Identification during the run session. 默认不勾选,若勾选则在运行期间屏蔽智能识别功能,也就是说,即使测试对象开启智能识别功能,只要在运行时勾选这个选项,智能识别就不会生效,可以说这个功能是一个总阀门。关于智能识别功能会在后续的“对象库”章节中做介绍。

(5)Save image of desktop when error occurs (if test is run by the HP Business Process Monitor). 在出现错误时,截图并在QTPReport中反应。该功能只限于业务组件的脚本运行,关于业务组件脚本的位置如图1-35所示。

图1-35

注意

要新建或者打开一个业务组件的必须条件是QTP和QC联通,否则会弹出错误信息,如图1-36所示。

图1-36

另附QC中的业务组件模块初览(图1-37、图1-38、图1-39)所示。

图1-37
图1-38
图1-39

上图就是QC9.0中的业务组件模块位置和业务组件概念介绍,在这里作者对这部分内容不多做阐述,如果有兴趣的读者可以自行研究,或问“百度大叔”或在51Testing论坛发帖等等。

2.File→Settings→Web

这个设置只针对B/S架构的系统,页面效果如图1-40 所示,这个页面下只有图中的“区域1”相对重要。下面,作者对“区域1”进行讲解。

Browser navigation timeout:XX seconds:设置运行测试步骤之前等待网页加载时间的最大值(默认60秒)。这个时间具体有什么用呢?举个直观点的例子,假设有一个脚本,内容很简单,就两个步骤,“1、进入51Tesing首页,2、点击注册按钮”,而访问网站的宽带最近又出了点小问题,打开51Testing网站的首页每次都非常慢,至少需要2分钟(120秒),那么此时 QTP 脚本在运行时就会报错。为什么?因为默认等待网页打开的时间已经超过了60秒,此时QTP就会执行下一个步骤“点击注册”,但是由于网页还没有打开所以走到下一个步骤的时候在页面上找不到“注册”这个测试对象,最终导致运行失败并报错。所以,此时的解决方案就是打开这个选项,然后将超时时间设置得更大。读者以后如果在项目中遇到类似的问题请记得这个小小的实用设置。

图1-40

这个设置在 QTP 10.0 的帮助文档内这样说明“The maximum time (in milliseconds) that QuickTest waits for a Web page to load before running a step”。请大家注意下划线部分,文档内标注的时间以毫秒为单位,但其实文档内写错了,实际情况是以秒为单位的,和QTP实际界面(图1-40)中的一样,实际界面中写的就是seconds而非milliseconds,请读者注意!

3.Tools→Options→Run

这是第二个关于脚本运行相关方面的设置,顺利进入界面后的效果如图1-41所示,这个页面下的大多数设置在项目应用中也经常会使用到,下面,对这些设置进行分解(没有标识区域的则说明不重要或基本不会使用)。

(1)Run mode (Normal or Fast):QTP在脚本运行时一共分两种运行模式。Normal模式是一种正常的运行模式,Fast则是一种快速运行模式。

先一起看一下正常运行模式,可以从图1-41中看到该模式下有这么一个设置“Delay eachStepexecution by:XX milliseconds”,这是什么意思呢?其实很简单,实际效果就是在运行回放时每一个步骤之间停顿的时间,默认是0,那也就是没有停顿,如果将其设置成2000(这里是以毫秒为单位的),再回放时,那么第1个步骤结束后,QTP就会停顿2秒钟时间再执行下一个步骤。

图1-41

好了,再让我们看一下快速运行模式,这种模式肯定就不可能有停顿的可能了,除了这个之外,作者在这里还要扩展一下知识面,如果以QC调用QTP脚本并执行,默认且只可能是以Fast模式运行的。

最后,再给各位读者看一下两个模式间的一个区别,如图1-42所示。

作者收到过很多测友提出的一个相同的问题,就是为什么在运行时没有黄色的箭头,是不是QTP有Bug?时有时无的。其实,出现这个问题就是这个设置的问题,如果选择了Fast,在运行的时候是不会出现黄色箭头的,切记!很多新人将运行模式设置成 Fast 了,见没了黄色箭头也不会想到是这个设置引起的,还以为是QTP的Bug呢。

图1-42

(2)Submit a defect to Quality Center for each failed step:任何一个步骤出错自动提交缺陷至QC。前提条件:QTP和QC连接成功,否则是灰色的。

(3)View results when run session ends. 默认勾选,当脚本运行结束后自动弹出Report报告。相反,把钩取消掉就不会弹出Report了。

(4)Stop command shortcut key. 停止运行的快捷键设置,默认是Ctrl+Alt+F5 组合键,并可自行设置。别小看这个快捷键,如果在脚本运行的时候想使其停下来,一定要用快捷键,想靠点击图标是很有难度的,自己试试就知道了,特别是长脚本,这也算是个小经验吧。

4.QTP的两种回放模式设置

当在回放QTP的时候,是否注意过QTP在回放的时候鼠标光标是没有运动的,有些读者肯定会问,既然经常要进行Click各种对象的操作,那为什么鼠标光标没有动,而QTP回放的时候却可以成功的点击页面上不同方位的对象按钮呢?其实QTP有两种回放模式:

Event 模式事件跟踪;

Mouse 模式鼠标跟踪。

Event模式就是平时默认用的模式,也就是事件跟踪模式。实际上,QTP的Click方法只是触发了对象的Click事件,而并未真正通过鼠标光标来进行点击按钮。我们使用的是Mouse模式的话,我们会看到回放的时候,鼠标光标是跟着对象走的,也就是鼠标光标跟踪模式。

下面来具体看一下是如何切换回放模式的,切换回放模式有两种方法。

(1)修改QTP的Options设置。

我们进入到 Tools→Options→Web→Advanced ,然后列表拖到最下面可以找到 Run settings下的Replay type,如图1-43 所示。

图1-43

可以看到QTP默认的回放模式是Event,也就是事件跟踪。如果现在切换到Mouse,点击确认后,回放时鼠标光标就会进行跟踪,读者可以试一下。

(2)以代码控制(作者推荐该种方式)。

为什么推荐这种方式,因为这种方式可以在 QTP 运行时根据个性化需求来进行控制,随时可以进行开和关,使用第一种方式就不能够达到这种效果,代码如下:

Setting.WebPackage("ReplayType") = 2

这句程序的意思就是把回放模式设置为2。1代表事件跟踪模式,2代表鼠标光标跟踪模式,现在应该很清楚了吧,这样就可以在QTP运行时个性化定制回放模式了。

那讲到这里,肯定会有读者问,那鼠标模式有什么用,我们平时默认的事件和跟踪模式不是都够用了吗?

接下来就说一下,为什么以及何时要使用鼠标跟踪模式。举些实例,如QTP运行时触发了Click事件后,应该弹出页面,却被IE给拦截了。而手工点击可以成功;还有当需要操作鼠标右键时等这些情况都可以临时把回放模式从事件跟踪模式切换成鼠标跟踪模式,让我们来看下操作鼠标右键的实例演示吧。

需求:实现右键点击Baidu主页中“关于百度”的链接

(1)首先,我们把这个链接对象添加到QTP对象库中,如图1-44所示(对象库相关内容在后续章节介绍,这里不多做阐述)。

图1-44

(2)添加完之后,输入脚本,代码如下所示:

Setting.WebPackage("ReplayType") = 2

Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("关于百度")._

FireEvent "onclick",,,micRightBtn

(3)回放之后就可以看到已经成功点击了鼠标右键,如图1-45所示。

图1-45

不知道还记不记得前面讲到要结合内容进行FireEvent这个方法的演示,在这个实例中,我们就用到了 FireEvent 这个方法,它是一个非常有用的方法,经常会在项目应用中使用到,在这里作者先附上一些关于这个方法的简单介绍,如图1-46所示。

图1-46

总结:本小节讲述了QTP的回放原理和项目应用中的相关设置,希望读者能够吃透这些知识点,并能在以后做项目测试时举一反三。

 

1.3.5 总结

本章节的内容主要讲的是QTP的录制与回放,市面上,任何一本书都会有这部分的内容。但是,作者对这部分内容进行了提炼,把其他书里的那些几乎等于QTP工具介绍的内容全部剔除,因为那些内容在实际的项目应用中几乎不会用到,保留了能切实在项目中用到的内容,通过自己的实战经验配合大量案例、实例(几乎每一个知识点都有例子)进行细致地讲解,希望读者在学习了本章后,能对QTP这个自动化测试工具的操作,以及如何把工具融合实际项目上有个整体的把握。虽然剔除了很多不需要的内容,但是,由于介绍的是 QTP的源头(就好比本章节标题一样“QTP 的开关”)而且配合了大量的实例,图文并茂,所以在完成本章节的编写后才发现原来还是需要用到那么大的篇幅才能将重要的知识点讲清楚、讲透。

在设计练习题的方面,作者思虑许久,考虑到本章节内容的性质,决定在本章节的巩固练习题中不设置实际操作题,本章节的练习题如果要出成操作题,无非就是传统的“录制与回放”,这样就会不由自主地偏离作者的原有思想。所以,作者决定以选择题(单选和多选)、判断题、排列题等各类有趣的形式出一份类似Exam一样的概念理论题,这些所谓的理论题其实是对整个章节内容知识点的贯穿,希望能起到巩固与复习的作用。

 

知识点巩固和举一反三练习

一、知识加强巩固趣味题之过5关(注:选择题可能是单选也可能是多选)

1、<排列题>请排列QTP 业务操作及执行流程的顺序。 ( )

A、录制

B、打开浏览器

C、回放

D、打开QTP

2、<选择题>QTP 的两种脚本运行模式分别是Normal 和Fast,它们之间的区别是什么?请在下面4个选项中做出正确的选择。 ( )

A、以QC调用的方式执行脚本,运行模式是Fast。

B、脚本运行时,如果左侧有黄色箭头,则代表这种运行模式是Fast。

C、Normal运行模式的执行速度最快。

D、可以在Normal运行模式中设置间隔时间,单位是毫秒。

3、<选择题>请在以下4个选项中选择正确的选项。 ( )

A、QTP停止运行的快捷键是Ctrl+Alt+F5,但不提供个性化设置。

B、QTP具有Event和Mouse两种回放模式。

C、QTP 具有Slow、Normal 和Fast 3 种运行模式。

D、QTP 具有两种录制模式,它们是Analog Recording 和Low Level Recording。

4、<选择题>请在以下4个选项中选择错误的选项。 ( )

A、假设在运行设置中选择Run on all rows选项,在QTP的Data Table中建立4行数据,其中第2行的值为空,则QTP在执行两次迭代后运行结束。

B、如果激活Run one iteration only选项,QTP 在运行时只运行1 次

C、Browser navigation timeout:XX seconds 就是设置运行测试步骤之前,等待网页加载时间的最大值,超出了该值后脚本直接退出并报错。

D、QTP 的运行模式设置具体位置在:Tools→Options→Web→Advanced→Run settings 下的Replay type。

5、<选择题>正确开启模拟录制(Analog Recording)的方法是: ( )

A、QTP 上方菜单栏→Automation→Analog recording。

B、直接使用快捷键“Shift+Alt+F3”。

C、在QTP界面上点击模拟录制的图标。

D、以上都是。

二、知识加强巩固趣味题之斩六将(读者有权审判它们的对错)

1、Setting.WebPackage("ReplayType")=2,这段代码可以灵活控制QTP的回放模式,“2”代表Event 跟踪模式,那么如果设置成“1”的话,QTP 就会切换到Mouse跟踪模式。( )

2、QTP 在录制过程中,遇到部分 Web 事件无法模拟操作,此时的解决方案就是进入Web Event Recording Configuration设置框并将Event configuration level提升至最高的High等级即可解决所有问题。( )

3、低级录制模式分两种:其中第一种是相对于指定窗口的录制,另一种是相对于屏幕的录制。( )

4、在开始录制之前,应关闭录制会话不需要的所有浏览器、网页或应用程序。( )

5、开启模拟录制模式前的必要条件是开启正常录制模式。( )

6、使用低级录制前无须开启正常录制模式,直接使用快捷键Ctrl+Shift+F3 即可。( )

作者认为,必须连过5关连斩6将才算切实掌握了本章节的内容,QTP“录制与回放”的重点,有一点差错都算闯关失败!

 

1.4 认清并请远离QTP的脚本录制模式

阶段要点

• 了解Keyword View结构。

• 摆脱Keyword View。

• 熟练掌握Expert View的代码结构。

 

1.4.1 QTP的两种视图及思维转换

从本章节开始,读者将真正开始彻底摆脱脚本录制,正式走向脚本开发的台阶。在开始讲解QTP脚本开发之前,首先需要详加介绍Expert View这个视图,这个视图是QTP官方指定的脚本开发唯一认可的视图。那么,以何为出发点以及如何介绍Expert View这个视图呢?决定以抛砖引玉的方式,利用脚本录制视图Keyword View形象地引出脚本开发视图Expert View。

相信只要稍许接触过QTP的读者就一定知道QTP提供两种视图,一种是Keyword View(关键字视图),另一种是Expert View(专家视图)。Mercury公司开发两种视图的本意是想让不同类型的人使用不同类型的视图。接下来分别对这两个视图进行讲解,并开始抛砖,直到引出一块良田美玉。

1.Keyword View(关键字视图)

通过关键字视图(一种图形化的视图),QTP 提供了一种模块化的表格格式,创建和查看测试或组件的步骤。在录制脚本的过程中,用户在应用程序上执行的每个步骤,在关键字视图中记录为一行,这样用户就可以轻松地修改任何一部分业务步骤。在这里拿“百度”的首页举一个例子,业务操作分3个步骤:

点击“图片”链接;

在图片搜索栏中输入“凤姐”;

点击“百度一下”。

在完成了这3个步骤后,关键字视图将包含下列行,如图1-47所示。

图1-47

图1-47中可以看到关键字视图非常直观有效,使用的用户可以很清晰地看到被录制对象的录制层次及运行步骤。但是,如果想自动化完成一些复杂的业务操作,在这张视图里是绝对不可能的,那就必须切换到专家视图里才行。专家视图等一切事宜就暂且搁置一下。先掌握关键字视图的界面、原理和工作机制。

在关键字视图中,一共分4列:Item、Operation、Value和Documentation。

Item:记录了所有对象。

Operation:该对象的操作。

Value:对象操作所用到的值。

Documentation:QTP自动生成的描述语句,描述了是什么对象,做了什么,怎么做。

关键字视图的介绍马上就要结束了,最后作者分解这个视图(语句会很随意)后会直接进入专家试图的解说。前面说过“在录制脚本的过程中,用户在应用程序上执行的每个步骤在关键字视图中记录为一行”,在本例中一共记录到6个步骤,如下:

打开浏览器;

进入百度首页;

点击[图片]链接;

进入图片页面;

在[搜索框]输入“凤姐”;

点击[百度一下]。

2.Expert View(专家视图)

瞬移成功,首先肯定是要讲专家视图的工作原理,“QTP 在关键字视图中的每个节点在专家视图中对应一行脚本”。读者可能一下子不明白这句话,那先来看两段代码,第一段代码是将关键字视图的工作原理用在专家视图上的错误代码,转换后的脚本如下:

Browser("百度一下,你就知道")

'图1-47中页面1部分

Page("百度一下,你就知道")

Link("图片").Click

'图1-47中页面2部分

Page("百度图片——全球最大中文图片库")

WebEdit("word").Set "凤姐"

WebButton("百度一下").Click

再看一下专家视图中正确的代码:

'图1-47中页面1部分

Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("图片").Click '句1

'图1-47中页面2部分

Browser("百度一下,你就知道")._

Page("百度图片——全球最大中文图片库").WebEdit("word").Set "凤姐" '句2

Browser("百度一下,你就知道")._

Page("百度图片——全球最大中文图片库").WebButton("百度一下").Click '句3

看完这两段代码以后,再回过头来理解专家视图的工作原理,专家视图和关键字视图是完全不同的,用通俗点的讲,专家视图并不像关键字视图那样,每个步骤都在视图中记录成一行,在专家视图中,必须定位到业务操作最终的对象,并且每一句的结束,以及最终的对象的业务行完毕为基准。在这里,最终的对象就是节点,专家视图中的一句代码是关键字视图中好多个步骤的结合。而那段作者自己伪造的代码就不是,每一句都不完整,要么有头没尾,要么无头有尾,这就是Keyword View和Expert View最根本的区别,下面,一句句看专家视图中的代码构成,先以“句1”来说,“句1”中集合了3个对象。

Browser——该对象如果出现必定是第一层,可以把它想象成打开的一个指定浏览器,具体哪个浏览器那么就由后面括号里的参数决定,如:Browser("百度一下,你就知道"),这样QTP就能很准确地识别到底打开的是哪个浏览器了。

Page——浏览器下肯定有各种各样的网页。那要定位这个对象也就很简单了,和上面一样,在后面的括号内加参数,如:Page("百度一下,你就知道"),这样 QTP 就知道了,原来是要定位一个叫“百度一下,你就知道”的网页,然后其他网页会一概不理!

Link——在定位了前两个对象后,终于可以定位到要进行业务操作的对象了。可是,页面上如果有好多Link呢,怎么办?只能和之前一样,在后面的括号内写进参数,如Link("图片"),这样QTP就不会乱了!好了,在最终找对了要操作的对象后,就可以给出指令,命令它做事情了,如需要它进行点击操作,那就给Link对象来个Click方法,到此,整个语句就可以完毕了。

分析:“句1”已经被拆解,作者在这里用最通俗的语言方式连贯地叙述一遍“句1”,希望能让新人听明白。→在一个叫做“百度一下,你就知道”的浏览器下的一个名曰“百度一下,你就知道”的网页页面上找到一个叫“图片”的链接,找到后,点击它。

小提示

在上面的例子中,是以Browser().Page().Link()的结构出现的,但实际上,在Web测试中并不只有这一种固定形式,除了Browser必定是在第一层以外,Page以及Link(或其他所有对象控件,如WebEdit等)都不是固定必须要接在前面那层的后面的,比如:

(2)Browser().Page().Frame().Link():Link对象跟在Frame对象后面而没有跟在Page后面。

(2)Browser().Dialog().Page().WebElement():Page对象跟在Dialog对象后面的一个例子。

接下来再看看“句2”,这句代码中需要注意Page已经变化了,变成了Page("百度图片——全球最大中文图片库"),然后在该页面中找到对象 WebEdit("word"),最后给这个对象一个 Set的操作方法并在后面写入参数,使得QTP在该页面上找到关键字搜索框,输入“凤姐”。

最后的“句3”唯一和前者的变化就是最终操作的对象不同了,Browser不变,页面仍然是Page("百度图片——全球最大中文图片库"),最后在前面输入好参数的前提下对 WebButton("百度一下")这个控件进行一个点击的操作,使得百度图片搜索引擎能够搜索到一些凤姐的照片。

************************************终极分析************************************

以上可以看到Browser对象一直使用的是同一个,随着Page对象的改变而分成了2个分支,在不同的分支上定位到不同的最终目标并赋予“动作”。所以,现在应该知道关键字视图中的代码结构了。就是通过这样的一层层定位,直到定位到最后的待操作对象,从而在Expert View下完美地组成一句脚本代码。

需要引出下一层对象用“.”,直到定位到最后一个待操作对象,然后仍然用“.”赋予其动作(各种不同的方法)。

小提示

在 QTP 中,要找到具体对象,如“图片”这个 Link,规则就是在对象大类(Link 类)后面以括号+引号的形式具体定位到那个Link控件,比如Link("图片")。需要注意的是,输入括号和引号乃至其他任何符号都必须是在英文状态下。切记!很容易出现类似的问题,在中文状态的输入法下打引号,结果QTP报错,自己找了好长时间也找不出问题。

概括&小结:

对于 QTP 来说,绝大部分的复杂操作都无法在关键字视图中实现,例如,要处理动态对象、需要定制个性化测试结果、获取对象运行时的属性值(Run-time Value)等。

QTP的核心编码语言是Visual Basic Script,因此,如果读者熟悉VBScript,就可以运用自如地通过编程方式在专家视图中设计复杂的测试脚本。同样,QTP 本身的对象库编程(Object Programming)和描述性编程(Descriptive Programming),这一切也都必须在专家视图中才能完成。

关于对象库编程、描述性编程、VBScript 编程、Run-time Value、处理动态对象等一系列知识都会在后面的章节中逐步向读者呈现。

 

1.4.2 总结

不知道有些读者会不会有这样的疑问,本书既然一向有“彻底抛弃脚本录制”的理念,那为什么还要写Keyword View(关键字视图)的内容呢,就算要写只一句话带过不就得了!作者由衷地希望有这些疑问的读者越多越好,这说明广大读者就是冲着“抛弃录制”的思想购买这本书的。现在听作者解释一下吧。

作者这么做就是因为想抛出一块好砖引出更好的玉,在抛砖的时刻(笼统、重点配合一个实例介绍关键字视图)如果能做,越有声色,后面引出的玉一定就能更好(将关键字视图中的步骤“画面”,一条一条转进专家视图使其成为脚本代码的一个解读过程)。另外,请重新回顾下这个小章节标题的后半部分“思维转换”。作者觉得更应该引导读者转换的是思想、思维,绝对不该是两个视图间的转换那么简单与粗糙。读者要从思想上去认识Expert View,如果光从操作上直接转向Expert View(直接在关键字视图敲击代码),表面上看很简单很轻松,但其实忽略了对专家视图的认识,也忽略了对 QTP 两个视图原理以及之间关系和不同点上的认识,如果这样走下去,作者觉得在今后脚本开发的学习道路上挫折会越来越多,地基打好的关键性大家都很明白。相信,本书的这一个小章节内容虽少,但是对今后的帮助不一定少!

 

知识点巩固和举一反三练习

一、大家来找茬(结合图1-48找出代码片中的错误)

图1-48

代码片如下:

Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("知 道").Click

Browser("百度百科——全球最大中文百科全书")._

Page("百度百科——全球最大中文百科全书").WebEdit("word").Click

Browser(百度一下,你就知道)._

Page("百度百科——全球最大中文百科全书").WebButton("进入词条").Set "51testing"

二、请根据图1-49中关键字视图的结构与步骤转化成专家视图中的代码。

图1-49

 

1.5 QTP精华——对象库(上)之基础攻略篇

阶段要点

• 初步了解QTP 中的测试对象模型。

• 明确Object Identification是管理对象模型的长官。

• 掌握智能识别原理、机制和各项设置。

• 对象库基本操作之添加、更新、对象闪烁、副对象库(Associate Repositorys)。

• 一个有趣的实验证明,做项目时手工添加对象的好处与效率。

• Export Local Objects与Export and Replace Local Objects。

• 掌握并熟练运用Object Spy。

• 明确使用公共对象库的必要与优点。

• 熟练驾驭对象库指挥官Object Repository Manager。

• Object Repository Manager的两个王牌级辅助工具初体验。

 

1.5.1 引言

如果说,上一章节是彻底摆脱脚本录制的一个良好的开端,是带领读者逐步走向QTP自动化测试项目开发的台阶,那么从本章节开始,读者将跨出巨大的一步,真正开始走进QTP脚本开发的世界。

在QTP这个自动化测试工具中,存在着两种脚本开发模式,第一种开发模式就是从本章节开始要逐步具体、深入、详细讲解的“对象库编程”。当然,本书的一贯原则是“实用原则”,所以无论是在上篇(本章节)还是下篇(1.6章节)都绝对不会详细地讲解在实际项目运用中用不到或很少会用到的知识点。想要精通对象库编程这个开发模式,并驾轻就熟地运用到自动化测试项目中,首当其冲就是要先“精通”QTP的对象库,作者讲的对象库其实是一个总称和概括,从大的方面包含对象库本身的功能、对象库的机制与原理、对象库编程知识、如何在实际项目中运用对象库编程等。

在上面作者主要针对QTP对象库的机制与原理以及对象库本身的功能做深入讲解,而对象库编程的部分则会在下篇中精彩解读。虽然需要掌握那么多知识的确很烦,也需要一个过程,但是作者认为上篇和下篇中的所有内容已经是最精简的了,所以,请读者务必对这些知识点做到“精通”,它们都是经常在实际项目中使用的,可以说是QTP脚本开发的必备技能!如果不能精通QTP的对象库,那一定不会是一名合格的QTP自动化测试工程师!

 

1.5.2 对象库的出现改写了软件测试历史

QTP 的对象库是这个强大的自动化测试工具的核心,也是其精华所在!有了对象库这一整套功能、机制,QTP 才可以在那么多的自动化测试工具中脱颖而出!QTP 的整套对象库功能与对象识别机制给自动化测试人员带来了前所未有的体验,它的成熟、上手度、良好的使用感受都是市面上其他任何自动化测试工具无法给予的。对象库是QTP在实际项目应用中的枢纽,读者一旦精通了它,会感觉到在项目应用、QTP 各项功能中都会和对象库产生必要联系。本章节的内容会结合大量仿真项目的应用来引导读者逐步精通对象库,希望读者能够做到举一反三,细细去品味对象库带来的不同感受(针对之前使用过其他自动化测试工具的读者效果更佳)!

小小的总结一下,可以说QTP在实际项目中的应用开发(特别是自动化测试项目做成功的案例)绝大部分都基于对象库编程模式,所以,对象库的出现改写了自动化测试领域的历史,也推动了这个技术领域走向更高的台阶!另外,先预告下,本章节以及下一章节的篇幅会很大,因为这两个章节的内容是QTP最精华的部分,也是整个第一章的最重要的一块,务必耐心学习。

 

1.5.3 一个简单的实例介绍对象库原理、机制及操作流程

1.5.3.1 对象模型的老大Object Identification和对象库的暧昧关系

在介绍对象库的原理与机制之前,首先说一下QTP自动化测试的原理,分以下3个步骤。

(1)封装真实被测对象并转化为QTP对象到对象库。

(2)对比对象库里的对象鉴别属性和运行时的真实被测对象的鉴别属性。

(3)对比后如果一致,则说明对象成功匹配并可以继续对该真实被测对象进行后续操作,如果两者不一致则报错,提示为对象无法识别。

我们可以看到,QTP自动化测试的原理其第一步就和对象库产生了联系,具体到底是如何联系起来的呢?其实很简单,在QTP里有测试对象模型这一个概念,它把各种对象都分门别类起来,建立出一个个对象模型,然后用这些对象模型来表示 Web 页面中的对象,比如 WebButton、WebList、WebElement 等各种各样的对象。每个对象模型都有一个可以唯一标识对象的关键属性列表,我们将前面这些连起来一块说,就是在添加对象至对象库后,QTP自动建立被添加对象的对象模型,并给出一个默认识别标识。然后,每个对象模型都有一个可以唯一标识对象的属性列表,这个属性列表是可以设置的,它就是Object Identification,先认识一下它,如图1-50所示。

图1-50

如图1-50 所示,可以看到这就是Object Identification 的界面,开启它的方法是:

QTP 上方菜单栏→Tools→Object Identification。

在Object Identification 对话框中设置的属性在添加完对象后就可以在对象库中查看到。如果觉得这些默认显示的属性还不够或者有的默认的属性是多余的,可以进行手工设置,看一下实例,通过实例来看最终效果,需要再一次借用百度的搜索框,如图1-51所示。

图1-51

这是一个WebEdit控件,也就是一个WebEdit对象模型,等会作者把这个对象添加到对象库中,添加两次,第一次不改Object Identification 中WebEdit 对象模型的默认属性,第二次剔除其中一个属性,然后一起看看它在对象库中的属性列表显示情况。先来看默认的情况,如图1-52所示。

图1-52

图1-52 中,作者标识了两个不同的区域Mandatory Properties和Assistive Properties。先知道它们的区别,Mandatory Properties 就是对象模型的必要属性,这个区域设置的属性在实际被测对象与对象库匹配时,只要有一个属性不一致就报错。Assistive Properties就没有这个规矩了,并且QTP默认所有的对象模型在这个区域中没有任何属性。

继续回到前面所讲,如图1-52中所示,可以看到WebEdit对象模型的默认必要属性有3个:html tag、name、type。接下来,开始添加百度搜索框这个WebEdit对象,并一起来看一下对象库中的属性列表情况,如图1-53所示。

图1-53

我们可以看到,对象库列表中的属性(Description properties)也是3 个:type、name、html tag,在Object Identification 列表中显示什么,对象库列表就显示什么。

小提示

关于 Test object details 列表中 Description properties(描述属性):在 Descriptionproperties 里定义的所有属性都是必要检查属性,都会和实际运行时对象的属性校验,如果匹配不上则报错,就以图1-53中的name属性举例,如果实际运行时,被测对象的name属性不是wd,则匹配失败,我们还可以根据项目实际情况额外地在列表下添加更多的必要检查属性,也可以筛检一部分,后续章节会有一些类似的实例。

那在Object Identification列表中删除一个属性,对象库列表中会有什么变化呢?会不会仍然一致呢?继续做实验,在Object Identification列表中删除html tag属性,如图1-54所示。

可以看到html tag 属性已经从Mandatory Properties 区域中消失了,关于如何让它消失或者复活,已经在图1-54中明示了。那么,再一次将百度搜索框添加到对象库中看效果,如图1-55所示。

图1-54
图1-55

实验证明:Object Identification 列表中没有的对象库列表中也不会有,如果读者哪一天发现预期结果不正确的时候,请提交缺陷给HP。

不知道读者是否还记得,在“1.3.4 QTP回放机制”那个章节里提到过智能识别这个概念,在Object Identification 里也有智能识别的设置按钮,在这里作者介绍下这个功能,并对QTP的智能识别做一些“合理的解释”。我们先来看下Object Identification 里的这个智能识别设置功能,如图1-56所示。

图1-56

首先,我们可以看到,在所有的Web对象模型里,每个对象默认是允许智能识别的(而Standard Windows 对象模型里的各类对象默认是不支持智能识别的),在这里的智能识别功能和“1.3.4 QTP回放机制”那个章节里提到的智能识别功能区别在于,这里的智能识别功能针对的是对象模型下的某一个具体对象,举个例来说,比如可以让WebEdit对象开启智能识别,但是不让 WebCheckBox 对象开启,而那个章节中的智能识别是一个总开关,假设这个总开关是打开的,那么例子中的情况就是WebEdit控件可以智能识别,而WebCheckBox控件则不行,那么假设这个总开关是关闭的,则在Object Identification 里无论你怎么设置,任何对象控件都不会智能识别,务必别搞乱了!

其次,在Object Identification 里,如果某控件开启智能识别(仍然借用WebEdit 对象为例),我们还可以对可智能识别的属性进行设置,如前面的图1-56中,点击Configure按钮就可以弹出设置框,设置框效果如图1-57所示。

从图1-57中可以看到,已经打开了WebEdit对象模型的智能识别设置窗口,左侧的列表中是这个对象默认的基本智能识别属性,这个列表中的一切属性是即刻生效的(即会首先智能识别这些基本属性),而右侧列表是备用属性,暂时是不会生效的,只有当左侧基本属性列表中的属性全部使用过后,仍然没有识别到的情况下才会生效,QTP会根据备用属性列表中的属性按着设定好的属性顺序来一个个继续智能识别,直到匹配到为止,当然连所有备用属性都不能识别后QTP就会报错了。这里需要注意的是,每个对象模型的默认智能识别属性都是不同的。在做项目的时候,一般使用这些默认的设置即可以应付绝大多数情况,毕竟这些默认设置都是Mercury公司设计出来的,相信他们也是考虑再三的,肯定具备一定道理和权威性。

图1-57

最后,在了解了Object Identification里的智能识别相关功能和回顾了之前的智能识别功能后,现举一个实例来让读者明白,智能识别这个功能究竟是什么?在项目应用中启用了智能识别后会发生什么?

实例:

先说个基本概念和原理,运用智能识别后,QTP在遇到对象识别出问题的时候,会尝试应用智能识别(Smart Identification),如果智能识别能定位出对象则继续执行脚本,反之则报错并提示错误信息,下面看一下这个示例脚本:

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园")._

Image("51Testing软件测试网").Click

以上脚本来源于51Testing软件测试网首页,如图1-58所示。

图1-58

对于“51Testing软件测试网”这个Image对象,QTP默认采用alt、html tag、image type属性来识别对象(见图1-59右下部分)。

图1-59

然而,当开发好上述脚本后,假设开发人员又在同一个页面添加了名叫“51Testing 软件测试网-老网站”的Image对象(现在用作登录老网站),同时修改了原来的“51Testing软件测试网”对象的alt属性,改成了“51Testing软件测试网-全新网站”。这样当针对这个新版本的页面重新回放上述脚本时,QTP 就不能基于alt+ html tag+ image type 的属性组合来识别原先的“51Testing软件测试网”(现在的“51Testing软件测试网-全新网站”)这个Image对象了,因为alt属性已经改了。但是QTP仍然能够正确地识别出这个对象,为什么呢?就是因为这个时候它开启并使用了智能识别功能(Smart Identifation)。

下面的过程描述了QTP应用智能识别来确认原“51Testing软件测试网”这个Image对象的步骤。

(1)根据Image对象默认设置的智能识别定义(默认智能识别属性是html tag),QTP首先从页面中找出所有html tag属性=IMG的对象(图1-55中可以看到html tag的属性就是IMG),前面也讲过了,在Base Filter Properties这个左侧区域中,定义的属性将进行第一轮筛选和过滤。

(2)如果第一轮匹配不到,那么就会在右侧的Optioanl Filter Properties(备选属性区域)中根据定义的属性顺序地进行筛选和过滤,请看以下步骤。

① QTP 会首先检查对象智能识别备选属性的alt属性(默认在备选属性里alt 在第一位,但是发现没有等于“51Testing软件测试网”的,因为已经被开发人员改为“51Testing软件测试网-全新网站”了。因此,QTP会忽略这个属性,继续应用下一个备选属性。

② QTP 接着检查对象的image type 属性(默认在备选属性里第二位),把image type 属性不等于“Image Link”这个值的对象过滤出去(图1-59 中可以看到image type 的值)。

③ 然后QTP 检查对象的html id 属性(默认在备选属性里第三位),发现所有其他的对象的这个属性的值都是“logo”(见图1-60中对应位置)。

图1-60

④ 紧接着 QTP 检查对象的 name 属性(默认在备选属性里第四位),发现有两个对象“51Testing 软件测试网-老网站”和“51Testing 软件测试网-全新网站”的 name 属性都等于“Image”(见图1-60中对应位置),因此QTP把其他的对象又一次过滤掉,只剩下这两个对象。

⑤ 于是QTP 再检查剩下两个对象的file name 属性,发现只有一个是等于“logo.gif”(见图 1-60 中对应位置),至此, QTP 结束智能识别过程,推断出这个对象是它要找的“51Testing软件测试网”对象,并且点击它。

当然了,如果在上一步仍然不能定位到对象,则还会依此类推继续下去。

图 1-60 是一个为已经添加至对象库的对象添加必要的识别属性的窗口。需要注意的是,在这个窗口里属性的位置显示是没有次序可言的,或者和Object Identification 里智能识别属性设置窗口中是不一一对应的,关于如何打开这个窗口和其他对象库功能的操作见下一个小章节。

1.5.3.2 以一个实例囊括对象库的原理机制与操作流程并揭开整个篇章

已经初步了解了测试对象模型、掌握了 Object Identification、QTP 智能识别技术,以及对象库的一些原理和机制,内容太多可能有的读者一下子难以消化,在这里再提示一下,演示一个简单的对象库编程的操作流程的实例来启发读者,也为以后更深入地学习打基础。请先看演示需求如表1-3所示。

表1-3 演示需求表
续表

添加对象之前,如图1-61所示。

图1-61

添加完对象后,如图1-62所示。

图1-62

脚本显示代码如下:

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Set "QTP自动化测试技术领航"

结果:

脚本运行回放完毕后,百度搜索框自动输入了“QTP自动化测试技术领航”,如图1-63所示。

图1-63

这样一个非常简单的实例演示结束了,接着继续更深入地探索 QTP 的精华对象库以及对象库编程。

 

1.5.4 对象库基本操作

在上一节中,对对象和对象库有了整体的认知,包括对象库编程在QTP中的价值、对象模型的含义、对象库的一些作用等。在上一节中有很多关于对象库的图例,这些都是作者事先设计好的,但是有些新人读者并不知道这些图例的效果是怎么设计出来的,因为本书还没介绍过对象库功能的操作,那么在本小节中,开始讲一下对象库功能的基本应用与操作,特别要申明下,本小节介绍的对象库指的是 QTP 对象库的功能意义上的操作,只是一些很单纯的操作方面的东西,就像如何将对象添加到对象库等,而不再像上一节那样指的是“对象库整体”。

首先,我们得知道对象库如何打开,默认有两种方式。

QTP 上方菜单栏→Resources→Object Repository。

快捷键Ctrl+R(推荐)。

上述步骤操作后,打开的界面如图1-64所示。

作者已经在图1-64中以数字标识了对象库功能中必须要掌握的操作,接下来将根据数字的顺序逐个介绍这些知识点(部分知识点配合实例)。

1.Test Objects

我们先来了解对象存放的区域,从 QTP 10.0 版本开始,对象存放区域被分为两块,HP的意图是将测试对象和检查点对象、输出对象区分开来。Test Objects顾名思义是存放着测试对象(图例效果以及关于如何添加测试对象在第6点,这里暂且略过)。

2.Checkpoint and Output Objects

检查点对象以及输出对象。QTP在10.0以前的版本是没有此区域的,但是感觉这块区域单独划分出来实用性不大,而且经过很多实践证明,Checkpoint and Output Objects在做实际项目时很少会被用到,作者仍然罗列出来的目的是把一些“现状”告知读者,最终是否使用由读者决定。

图1-64

3.对象库中的Action切换

首先要注意,这里的Action切换只是对象库中的切换,别和对象库外面的Action切换搞混了。在这里,可以通过它查看不同Action下的对象,很好的一个功能,可以非常直观地为对象归类,用户在使用时也可以快速查阅不同Action下所属的对象。同时,当需要添加对象时要注意切换到不同的Action再添加对象,比如当前脚本下有Action1和Action2,如果我们需要在Action2中添加其专属的对象,那就需要把Action切换到Action2后才能添加对象,只有这样对象才会被添加到Action2中。如果仅仅只是建立了Action2,但是添加对象的时候没有切换到Action2(即仍然停留在Action1),此时添加的对象自然是在为Action1添加,很容易忽略这个小细节,请务必注意。

此外还要注意一点,假设脚本调用了外部Action,那么对象库中Action一样可以切换到那个外部的Action,但是只有查看对象的权限,而没有添加、删除、更新、编辑、亮灯等权限(灰显),大家可以看一下效果如图1-65所示。

4.对象的剪切、复制、粘贴与删除

这些功能是软件必备的功能。这里作者拿剪切和删除为例告知读者一些该注意的地方(剪切和复制大同小异,无须重复举例)。先看一下图1-66所示。

如图1-66所示,现在如果需要将51Testing的搜索框对象剪切到百度的Page页面下,非常简单,只需要点击对象,然后使用图标或者快捷键 Ctrl+X,再选中百度的 Page 进行粘贴即可(这个效果就不附带例图了,大家都能明白)。

图1-65
图1-66

这里作者要提及的是如果剪切(或复制)的是父对象,那么粘贴后,其子对象会被一起剪切(或复制)过去,比如现在把百度的Page对象剪切到51Testing的Browser对象下,效果就会如图1-67所示一样,“百度一下,你就知道”这个Page对象以及其下的“wd”子对象被一起带到51Testing的Browser对象下,并且与51Testing下的Page对象平行。

删除操作也一样,如果删除父对象,则所有子对象一并被删除,现在删除 51Testing 的Browser对象试一试,删除后效果如图1-68所示。

图1-67
图1-68

如图1-68所示,51Testing的Browser对象一旦被删除,其所有内容一并被删除。

5.对象库中对象的查找与替换

QTP 的对象库为用户提供了非常快速且方便的GPRS导航系统,它就是Find & Replace功能,快捷键Crtl+F。认识一下这个功能的界面,如图1-69所示。

打开这个功能后就会出现图 1-69 中的界面效果,上半部分是查找功能,下半部分是属性替换功能,在这里就可以将对象的属性值直接替换掉。

图1-69

6.添加对象

这个功能是罗列的11条里最重要的,没有添加对象也就没有后续功能了。这里需要给读者解释一下,作者本该把最重要的放第 1 条,但是为了文章的连贯性(如对象库中图标的排列顺序那样,这个按钮也没有排在第1个),所有内容顺序也尽可能与其图标位置相呼应。下面开始添加一个对象。

步骤如下。

第一步,点击Add Object to Local按钮,在点击后会出现一个白色手指。

第二步,拖动白色手指至待添加的对象上,点击鼠标左键。在这里仍然以百度搜索框为例,来看一下点击后的效果图如图1-70所示。

图1-70

在图1-70中可以看到,在选中并点击对象后,还不算是添加对象完毕,QTP此时还会弹出一个对象选择框,用来做最后的选择。即从图1-70中可以看到,虽然只选中了百度搜索框,但同时这个名为“wd”的百度搜索框的两个父对象也会一起显示,如果此时假设选中 Page对象,则最后添加进去的对象是这个Page,外加它的父对象Browser。所以,到了这一步只能说快接近完成一个对象添加过程,但是没有真正的结束。最后补充一个概念:当子对象被添加时,其父对象会一起被添加至对象库,而当父对象被添加时,如还有祖父对象,则父对象连同祖父对象一起被添加至对象库,但其子对象不会被添加,新手务必牢记。

第三步,最终确认要添加的对象,确认无误后点击OK按钮。

总结:在完成了以上3个步骤后,对象就添加到对象库了。实际效果如图1-71所示。

图1-71

另外,打个比方,现在需要添加百度首页上的另一个Link对象“贴吧”,它们属于同一个页面的,在添加完后,这个对象就会直接隶属于它的父对象下,如图1-72所示。

图1-72

小提示

当添加对象时,一旦白色手指出现以后就无法再继续页面上的任何操作了,如点击、切换网页、拖动滚轴等,因为只要有任何“左击”的动作,它就会帮你添加对象。假设如果在一个页面上添加对象后,需要切换到另一个Web页面添加另一个对象怎么办?一般的办法就是添加好一个对象后,暂时先不激活白色手指,等网页切换了以后再回到QTP界面切换手指,但这样会繁琐。添加一个、两个对象还好,如果要添加很多对象呢?会一直在页面和QTP界面中来回切换。Mercury公司当然预料到了这个情况,他们提供了一个捕捉模式切换功能。在这里作者先不讲这个功能,也只是做个预告。作者会在介绍到本章节的Object Spy这个重要的知识点时,分享这个实用又贴心的功能,添加对象和Object Spy是共享这一功能的,因为它们都需要捕捉,所以都具备捕捉模式。

这个功能点已经讲完了,但是读者还记得在1.3.1节中请拒绝“录制”,再开始你的实际项目之旅中的1.3.1.2节一些“理论性的社会实际问题”实例吗,作者在末尾段说过要做一个实验来证明以手工添加对象的方式效率远远胜于录制添加的方式。如果已经记不清了,请看下面这段加了引号的原文:

“另外,在添加对象方面上,录制也显得差强人意,因为靠录制的方式添加对象,表面上来看十分快速,但是通过这种方式添加到对象库中的对象,它们的命名都是QTP自动命名的,相当的乱,还是需要一个个去改,而且很多对象还是不需要的,QTP也给自动添加进来了,这样弄下来,效率远不如一开始就老老实实一个个添加对象,并根据规范为它们逐一命名再进行编程呢。”

现在应该回忆起来了吧,作者将借用51Testing论坛的注册页面来做个小小的实验。先来看一下真实环境的界面,首先是进入 51Testing 软件测试网的首页,并在页面的上方找到“注册”按钮,点击进去,如图1-73所示。

图1-73

在进入了图1-73中的注册页面后,实验就要开始了,我们的业务流程是完成一次注册,所需要使用到的控件作者也已经排列出来了。对于添加对象的方法“是否效率”,暂且先不做对比。在此就先用录制的方式添加这些对象(所谓录制添加的方式就是指在录制这些业务操作的同时,对象会以QTP默认的设定自动添加到对象库),在完成了操作以后,看以下3张相当直观的例图,界面操作图(1-74)、脚本代码图(1-75)、对象库图(1-76)。

简单插一句:界面操作图没什么可说的,是作者刚才在做的事情。

作者有话说:脚本代码图1是录制完毕后,QTP生成的脚本,读者看看这个脚本是否直观?是否简洁?是否优美?作者就此询问了两位QTP初学者,他俩都给出了自己的观点。

甲说:“QTP 写的脚本简直太完美了!”

乙说:“感觉不是很直观、精简,应该还可以优化许多!”

作者在这里只会支持“路乙”为什么?请大家看下脚本代码图 1(图 1-75)中第 13、14行和第16、17行代码,这4行代码是对同一个对象控件的操作,读者无论之前是亲自同步操作的或者是看了作者的操作的,请大家讲一下,这个对象控件是刚才操作的哪个对象?相信大部分读者都不好理解。这是很正常的,看着脚本里的“WebEdit("secanswer")”,谁又会在过了1分钟、10分钟、1小时、1天、10天后重新查看脚本(维护脚本)时还牢牢的记住它是一个“验证回答的输入框”对象?当然,在这个超级简单的脚本中,大部分对象控件我们还是比较熟悉的(QTP 在录制时为其默认生成的对象名),比如第2 行的“WebEdit("username")”一看便知是“用户名输入框”对象,或者会有读者反驳说,自己刚才能迅速反应出是什么对象!那请迅速地告诉自己第20行和第23行的“WebEdit("seccodeverify")”是什么对象?!

图1-74
图1-75

在这么简单的一个脚本中就已经出现了2处几秒钟后就会令人“费解”的对象,那更别说十天半个月后的脚本维护工作了,估计那时候打开这个脚本看到这两个对象已经完全不记得它们是什么了!那如何才能有效地避免类似的事情发生呢?作者先不说,请读者继续往下看。

再继续找找这个录制出来的脚本的“茬”!大家有没有发现每行代码都特别的长?长到作者必须要通过换行才能把这张例图的内容完全截取下来,不然肯定有一部分代码无法显示了。截图也就不说啦,就说QTP界面,估计这么长的代码也是无法在界面中全部显示的吧?要通过滚动条才能看到末尾的代码。

现在可以开始解释了。QTP录制出来的脚本真是不太直观!那如何应对?做到直观、简洁并使代码显得更加优美?那就是替录制生成的对象“整下容”,个性化定制自己觉得舒服的名字,比如在这里完全可以将“WebEdit("secanswer")”改成“WebEdit("验证回答")”,将“Browser("51Testing软件测试论坛软件测试|")”简化成“Browser("51Testing软件测试论坛")”,将“Page("51Testing 软件测试论坛 软件测试|")”简化成“Page("51Testing软件测试论坛")”等。这样代码就直观、很精炼了。另外需要注意的是,对象类型如WebEdit是不可以更改的,只能修改其括号内的Name。

不过,不能在脚本里直接改,必须要在对象库里改,否则运行的时候对象库里的对象和脚本里所描述的对象就不匹配了,会导致报错!那就进入对象库,先看看“对象库图1”图1-76所示。

图1-76

先不说怎么为对象改名,当务之急是要继续找对象库的“茬”!图1-76中的这些对象就是在录制时同步添加进对象库的,是脚本里所有涉及的对象。我们可以看到,在这个对象库中呈现出,有的对象默认以中文命名、有的对象却又默认以英文命名,而有的对象的默认命名不够精简。其实这些“茬”刚才在“脚本代码图 1”中是同样存在的,只是作者有意将其留到这里。作者找出这个“茬”也不是没根据的,同样地请读者看这份对象库列表,你能迅速而准确地告诉自己每个对象符号代表着哪个对象吗?结论很明确,“茬”也找的差不多了,解决办法前面也讲过了,就是通过先进的科技手段为这些对象“整容”!怎么整?下面作者为读者做个示范,将图1-76中最下面那个WebEdit对象“username”弄成“用户名”。

步骤如下。

第一步,选中“username”这个对象后,将光标定位到右上角的“Name编辑框”,输入“用户名”,如图1-77所示。

图1-77

第二步,随意点击一下界面任何位置,目的是为了完成Name的变更,相当于点击“确定”的功效,“整容”后的效果如图1-78所示。

简单两步,“整容”完毕!可以很清楚地从图1-78中看到“username”,从此以后将以更易理解的“用户名”展现给大家。另外再来看看脚本中的第2行代码,发现对象在对象库中更改名称以后,在脚本中也会自动更新,可以看到在脚本中原先的“WebEdit("username")”同步更新成了“WebEdit("用户名")”。

图1-78

这个小功能还是比较常用的!

接下来展现一下作者已经全部修改好的对象库与脚本,见脚本代码图2(图1-79)、对象库图2(图1-80),看这样是不是优化多了!

图1-79
图1-80

这样处理过的时间长了再回来看脚本和对象库也是一目了然的。但是,这些都是作者之后的补救工作,是后面才改的,这样也会存在不少风险,有时候稍不留神就会改错,要知道对象改错了是会影响脚本的。同样也相当浪费时间,还要在对象库中一个个去识别这些陌生的对象,那还不如在一开始添加的时候就一边添加一边改名呢,这样就绝对不会遗漏和弄错,同样也节省了很多时间!

最后,我们来做个设想,这个业务是非常简单的,对象控件也比较少,我们还能勉强改过来,那如果碰到业务相当复杂、对象控件相当多的情况呢?还能那么轻易地修改吗?读者还可以跟着作者做一个实验,用手表或计时器看看手工添加对象速度快还是录制后修改来的快!前提是效果必须不能比“脚本代码图2”和“对象库图2”中的效果差,至少也得保持一致。顺便提醒一下:对象越多、业务越复杂,“手工添加”越能超过“录制后修改”!

7.对象更新

当版本更新后,原先的脚本由于对象变化导致无法顺利运行,此时就可以使用这个功能进行更新,操作步骤和添加对象的3个步骤完全一样,只是按钮不同,这里不再重复。另外需要注意的是,假设在对象库中选中的是WebEdit控件,但是想更新成Link控件,则会报错,如图1-81所示。

图1-81

虽然无法更新不同种类的对象控件,但是同种类的控件可以随意更新,切记!另外,作者在做项目时,也碰到过一个现象,就是对象其实没有改变,但是仍然由于对象识别不了而脚本报错了,此时,也可以使用对象更新功能,更新一下就好了。一直不确定为什么会如此,但是的确很实用,也算是作者的一个经验分享吧。

8.对象闪烁(亮灯)

Highlight in Application功能可以使对象在程序或者Web网页上闪烁,非常的显眼、高调!在实际项目中,这个功能使用率很高,大多出现在调试脚本的时候。作者就经常在脚本出现错误时(由对象不能识别引发的错误),首先先“亮灯”,看看能否定位到对象,如果能“亮灯”就说明对象本身是能识别的,可能是因为其他原因综合导致对象假象性的无法识别,当然如果不“亮灯”,那就很明显是对象属性变更导致的识别不了对象。好好地利用“亮灯”技术可以给脚本调试带来很多便利。

脚本错误的原因可以说是千变万化,调试脚本、定位错误绝对是门技术活,在这里就可以靠“亮灯”来一步步定位,排除可能性。反正,只要能成功定位脚本错误的具体原因,无论是什么方法,都是好方法,在今后的内容中,作者也会尽量多列举些这方面的内容。

补充一个小知识点,这个“亮灯”功能有一个Highlight的隐藏方法,如果将代码写入脚本,那么当执行完这句代码以后,本句代码的对象在程序或Web页面上同样会进行闪烁,效果和点击图标是一样的,在某些特殊情况下脚本调试时会运用到。举个例子,下面这句代码就会使“wd”这个WebEdit对象闪烁:

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Highlight

9.初步认识下Object Spy

在打开对象库以后,也有一个Object Spy 功能,这个功能和另一个QTP 内置Object Spy是一模一样的。Mercury 把这个功能也放进对象库应该是为了让用户使用更方便。在这里,读者暂时先知道对象库里也有一个就可以了,后面的小节中会重点讲解ObjectSpy相关知识。

10.Associate Repositories

这个功能的中文名叫副对象库,形象点可以把它看成一名开长途车的“副驾驶员”,当主驾驶累了副驾驶可以顶上继续长途跋涉。这个副对象库功能在实际项目应用中经常会被使用到,可以根据具体的业务情况事先封装好一些项目要用到的对象,并组合成一个对象库文件,在需要时就可以调用这些对象库文件到对象库中,成为一个副对象库。不过使用副对象库功能会有一个弊端,就是在加载后会产生很多ObjectRepository.bdb文件,读者需要了解一下。那么接下来,让我们先来看一下具体是如何调用的,图1-82就是打开副对象库后的窗口界面。

图1-82

图1-82就是打开副对象库后的效果,界面非常直观,操作也相当方便,作者在这里就不对如何操作做过多的阐述了。界面中一共有3块区域,已经在图中标识了,接下来,让我们一起动手做一个完整的实例。

预备工作。

(1)事先准备两个对象库文件作为副对象库,分别命名为link.tsr以及edit.tsr(其中link.tsr内置“百度”首页上的“视频”这个Link对象,而edit.tsr内置“百度搜索框”)。

(2)启动QTP。

(3)准备两个Action(除默认的Action1外再新增一个Action2)。

(4)开启对象库并将库中的Action切换至Action2。

(5)进入“百度”首页,将“百度一下”这个WebButton测试控件添加至对象库。

暂时不用管.tsr 对象库文件是如何生成的,在本小节最后的补充知识点中,以及后续介绍Object Repository Manager那个小节中都会讲到。

要求&完成目标。

(1)不得再添加任何对象控件。

(2)使用已有资源并利用副对象库功能完成以下业务。

在Action1 中点击“视频”链接。

在Action2 中输入“QTP 自动化测试技术领航”并点击“百度一下”。

(3)Action2很有可能以后会添加新业务,所以,需要在Action2中包含所有已知业务所需的对象,即“视频”这个Link对象也需要存在。

(4)无须写脚本代码,只需相应地设计对象库即可。

首先回顾一下刚学过的知识(3.对象库中的Action切换),在上述描写的预备工作中的第4点中我们将Action切换至Action2了,所以在完成了第5点后,此时“百度一下”这个测试控件被添加在对象库中的Action2里,而Action1里是没有这个对象的。

接下来开始“审题”并依次进行解题,请看以下步骤。

第一步,不得再添加任何对象控件。

本点要求不得再添加任何对象控件,所以,必须也只能使用副对象功能才可能完成任务。

第二步,在Action1中点击“视频”链接。

要完成此步则必须将“视频”这个对象添加到对象库中,所以,需要将link.tsr文件导入副对象库,如图1-83所示。

我们可以看到 link.tsr 文件已经被导入到副对象库中(路径自定)。但是,此时尚未完全成功,还需要一步,就是将这个link.tsr文件具体分配到Action的操作。在图1-83中可以看到,在可用Action区域中一共存在两个可用Action,这两个Action就是在脚本中建立的,脚本Test中有多少个Action,这个区域就有多少个Action。

图1-83

小提示

什么是脚本Test?请先看图1-84和图1-85所示。

图1-84
图1-85

我们来看上面两张图,通常建立的最基础的脚本就是Test(图1-84),在Test Flow中, Test下会以列表形式显示所有Action及其执行逻辑与顺序(图1-85)。

根据业务要求,我们把Action1拖至右侧的已用Action区域(Action2暂时还没用不动它),如图1-86所示。

图1-86

在图1-86所示的步骤完成后,点击OK按钮,整个操作完成,link.tsr文件中的对象也将成功载入到对象库的Action1中,如图1-87所示。

图1-87

如图1-87,有了对象,就可以开始对象库编程了,不过需要注意的是,从副对象库中引用的对象是灰色的,无法编辑的,如果想编辑对象,则必须先将其变成本地对象,这个在这里就不多讲了,后面会在“11.对象库的切换”中讲到。

第三步,在Action2中输入“QTP自动化测试技术领航”并点击“百度一下”。

这个步骤很有意思,这里需要先输入再点击这两个步骤组合完成。我们在预备工作中已经为Action2添加了“点击”所需的对象了(图1-88),现在就需要通过导入副对象库的方式组合进来。我们把“输入”所需的对象给添加进来,步骤不再重复,直接忽视,最终效果如图1-89所示。

图1-88
图1-89

下面就可以根据业务要求正确地在脚本的Action2中进行对象库编程了。

第四步,Action2很有可能以后会添加新业务,所以需要在Action2中包含所有已知业务所需的对象,即“视频”这个Link对象也需要存在。

这一步唯一要做的就是把“视频”对象同样添加到 Action2 中,以备不时需要。“视频”对象在 link.tsr 文件中,在添加前可以看到目前该文件中的对象没有出现在 Action2中(图1-89),就是因为在设置时没将Action2从可用设成已用(见图1-26)。所以,只需要将Action2“右移”就可以了,步骤直接忽略,最终效果如图1-90所示。

图1-90

在“视频”对象被添加进Action2后,目标也就完成了。不过相信细心的读者会发现一个问题,大家先把书翻到前面看图1-87,在link.tsr文件被加载后,Action1中的所有对象都是灰色显示的,这代表这些对象是从副对象库中加载的,那为什么到了Action2中,只有“视频”这个子对象灰色而其父对象与祖父对象不灰色(请看QTP当前环境,也可看图1-90)?其实道理很简单,“视频”、“百度一下”、“wd(搜索框)”都是子对象,它们的祖父对象 Browser 以及父对象Page是3兄弟共有的。之前已经完整操作过一遍了,添加“百度一下”是添加到本地对象库的,所以,其父对象Page以及祖父对象Browser也属于“本地对象”,“本地对象”是不会灰色且可编辑的,这个毋庸置疑。那么在“视频”对象加载进来后,由于它的祖父对象和父对象与Action2中的完全吻合,QTP会在吻合的时候进行合并,“户主”还是原来的“本地对象”,所以“视频”对象只能自己灰色,QTP绝对不会允许它改变它祖父和父亲的“户籍”,这就是QTP的一个规则,虽然不是很重要,但是还是需要为读者揭开这个谜团。其实在之前加载“百度搜索框”的步骤时就已经出现了这个情况,“wd”灰色而其祖父Browser与父亲Page不灰色。

到这里为止,整个实例过程讲解全部结束,这个实例还是比较细致的,在分步讲解过程中,也扩展穿插了一些小知识点,希望读者能够完全掌握“副对象库”的使用方法并做到融会贯通!另外需要注意,点击QTP 的上方菜单栏Resources→Associate Repositories,同样能够打开副对象库,入口不同但是结果是相同的。

在结束第10小点之前,作者还要分享一句代码,它就是本书中会陆续讲到的3大实时动态加载的第1个之“动态对象库加载”,代码如下所示:

RepositoriesCollection.Add "D:\QTP自动化测试技术领航\link.tsr"

这句代码写在脚本中,一旦被执行到以后会触发加载对象库文件使其成为副对象库的事件,效果和手工添加副对象库完全一致,只是没有了选择Action并加载的步骤,因为没必要,把这句代码写在 Action1 中,则说明加载到 Action1 中;添加到 Action2 中,则代码加载到Action2中,依此类推。通常,把3大实时动态加载的代码写在脚本的最前面几行,另外需要注意的是,3 大实时动态加载的生命周期都很短,脚本执行结束它们也就结束。下面提供一个用VBScript后台语言动态调用副对象库的函数供读者参考:

Public Function AddObjectRepository(objectrepositoryname)

Dim Pos

'判断:如果已存在".tsr"后缀名则直接使用该文件路径,如果不存在则添加后缀名

If instr(objectrepositoryname,".tsr") > 0 Then

RepPath = objectrepositoryname

else

RepPath = objectrepositoryname & ".tsr"

End If

'初始化:如果存在残留的副对象库则删除

RepositoriesCollection.RemoveAll()

'添加副对象库

RepositoriesCollection.Add(RepPath)

'添加后的验证:查找副对象库并将值返回给变量,如果存在返回1

Pos = RepositoriesCollection.Find(RepPath)

MsgBox Pos

'返回的值如果不等于1代表不存在则报错

If Pos <> 1 Then

MsgBox "找不到副对象库!"

End If

End Function

'调用该函数

Call AddObjectRepository("D:\QTP自动化测试技术领航\link.tsr")

11.对象库中对象类型的分类与切换

这个功能相对比较简单,其更大的意义在于方便用户操作,可使对象库的类型根据实际操作进行准确而快速地分类,它是以下拉框形式出现的,默认情况下只有All Objects和Local Objects两个类型,含义就如同其字面意思,不多做解释了。

接下来做一个实验,首先需要有低碳的理念,所以原材料仍然复用之前的link.tsr 文件,在导入副对象库并应用到Action后,再添加一个“百度搜索框”(本地添加)。在这些准备工作全部完成以后,可以看到对象库中又多了一种对象类型link.tsr,这个其实就是副对象(也可叫作辅助对象),以导入到副对象库的对象库文件名显示,可以有多个不同的副对象,它们的命名也各不相同,但是都属于同一个种类。分别来看一下各种对象类型的实际图例,如图1-91、图1-92、图1-93所示。

图1-91

如图1-91 所示。All Objects下显示了所有的对象,其中副对象“视频”以灰色显示,但是其父对象Page和祖父对象Browser没有灰色,被转化成为本地对象,因为它们另外还有个身为本地对象的后裔“wd”,这个知识点在前面的内容中已经讲解过了,希望在这里能起到一个复习的作用。

图1-92

如图1-92 所示,Local Objects下正确显示了手工添加的本地对象,副对象是绝对不会在这里出现的,如果出现请将Bug提交给HP公司!

图1-93

如图1-93所示,可以看到所有的对象都是灰色的,这就足以证明它们是通过特殊渠道进来的,这里会显示link.tsr文件下的所有对象。除此之外其他任何本地对象都被排除在外,如果有多个副对象被添加进对象库,它们也只会各司其职,绝对不会发生link.tsr中出现edit.tsr中的对象的错乱情况。

在这里还需要提到一个功能,可以看到,图1-93 中的这些对象都是不能编辑的。在讲“副对象库”的时候就讲过,由副对象库导入的对象是无法编辑的,要编辑的话就必须使其先“转职”成本地对象库(即主对象库)。怎么“转职”呢?很简单,在你需要“转职”的对象上点击右键后,再点击Copy to Local 即可,现在要把“视 频”这个对象“转正”了,来看下面的操作实例,如图1-94所示。

图1-94

请注意图1-94 中的两个方框位置,先来看左下角的这个,Copy to Local 是灰色的,这是怎么回事?刚才还不是说副对象可以转成本地对象的吗?那为什么这个功能灰色了?请看右上角的方框,此时,对象库的对象类型是link.tsr,也就是副对象,而要使对象“转职”必须切换到All Objects下进行,操作实例如图1-95 所示。

同样先注意两个方框位置,这个时候可以清楚地看到Copy to Local 可以点击了。点击后即宣告“转职”成功,需要注意的是在“转职”后,原先的副对象库文件是绝对不会受到影响的,因为“转职”只起到了 Copy 作用,它并没有改变文件自身内容的本领。另外还需要注意一点,“转职”跟复制、剪切、删除对象是相反的,父对象一旦“转职”了,祖父对象也受影响跟着“转职”而不会制约子对象,复制、剪切、删除则是父对象制约子对象,而祖父对象不受任何制约,正好相反,读者可以多加尝试!

图1-95

知识点补充。

以上的11点全部讲解完了,除此之外,作者再介绍一项图中没有用数字标识出来的对象库导出(替换)功能,在项目应用中也时常会使用到,先看这个功能出自于哪里,如图1-96所示。

图1-96

上图1-96所示就是这个功能的具体位置,File菜单下有3个子菜单,其中Close就是关闭对象库,这个太简单了,主要说一下“Export Local Objects”和“Export and Replace Local Objects”,这两个功能的共同点是,它们都可以导出对象,前者就是最单纯的导出本地对象,而后者稍许复杂点,除了导出本地对象以外还有一个“代替”的附加功能,这个附加功能的实际效果是什么?让我们一起来看两个实例。第1个实例就是最简单的导出对象,操作实例图1-97所示。

通过图 1-97 中的操作,就可以保存一个对象库文件到指定文件夹中了,之前一直用的link.tsr就是这么来的,这个是最简单的,接下来主要讲讲后者,在讲之前先做一下准备工作。很简单,在新脚本里添加一个“百度一下”按钮就可以了。继续,后者其实就多了一个“替换”的附加功能,作者起先误以为是保存文件的时候,如果命名相同则会覆盖,保留下新的文件内容,但是仔细想想就觉得不对,这好像有点多此一举,因为Mercury并不需要单独开发这个功能,Windows 系统现成的就有这个功能了,那这里的替换到底是什么?作者其实也不大明白……那我们现在怎么办?还记得1.2中学到的知识吗?通过帮助文档“F1”找到想要的答案,在输入关键字“Export and Replace Local Objects”后,“F1”终于揭开了真相,如图1-98所示。

如图1-98 所示,帮助文档已经写的非常清楚,原来选择Export and Replace Local Objects后,这些对象就会自动替换成副对象(也叫辅助对象),以副对象的身份出现,其本地对象的身份将被剥夺,原来这里的替换含义是将本地对象替换成副对象,实际效果就是导出这些对象并自动替换成副对象来使用,那么将其导出,就命名为“实例 2.tsr”,并且来验证一下到底正确不正确。需要验证两点:第一点,副对象是灰色的,那我们来看究竟有没有达到预期结果(读者也可以自己在本地环境上同步试验),如图1-99所示。

图1-97
图1-98
图1-99

第一点通过了,那么接下来验证第二点,副对象库里是否存在刚才被导出的文件,打开副对象库,如图1-100所示。

图1-100

我们可以看到,在副对象库中的确存在“实例2.tsr”这个文件,并且当前Action自动会从可用区域移至已用区域,这也就意味着该文件中的对象已经在履行副对象的使命了。至此,试验结束,验证通过,和“F1”里描述的毫无差错。通过这两个实例,相信读者应该可以理解导出对象的两个不同的概念及其运用了。特别是后者,如果能在实际项目中举一反三且灵活运用的话,一定可以化繁为简,并很大程度上提高对象维护的效率。

本小节的内容针对对象库功能的基本操作,但是都是非常具有实用的,扩展操作或高级操作如共享对象库、对象库合并等知识在后续小节中讲解。

 

1.5.5 Object Spy让对象无处藏身

1.5.5.1 结交新朋友——侦探Jack

做基于界面的功能自动化测试,其归根到底就是对界面上的对象控件做文章。想要掌控这些“五花八门”的对象控件,就一定要深入地去认识它们,只有掌握了它们的内部结构,自动化测试工程师才能把测试工作做起来。内部结构是什么?其实就是一个个(大批量)的对象属性,正是利用这些属性才能控制这些对象控件,以便使用它们做每一件事。不过,对象控件不是万能的,它们都有自己的业务范围,所以,它们只对范围内的有效!

那么,该如何去探知对象控件的内部结构呢?有两种办法:第一种,自己识别对象控件的内部结构!如果第一种办法不适合你或者你没法实现。那么第二种办法就是获得一种探测器工具,用它可以轻松探测各类对象控件的属性。在这一小节,作者将讲解第二种办法。

市面上,有很多自动化测试工具内置这样一个探测器,因为只有探测到了对象控件的内部属性,才能继续将自动化测试做下去。如果没有内置的探测器,也一定要去寻找一个独立的外部探测器来配合使用。QTP直接提供了一个重量级的探测仪,它就是Object Spy,它一定会是你自动化测试旅途的“贴身伴侣”,让我们来认识一下这位新朋友,有3种方式可以调用它。

(1)QTP 上方菜单栏→Tools→Object Spy。

(2)QTP 默认显示工具栏中点击Object Spy的图标,如图1-101 所示(推荐)。

图1-101

(3)打开对象库,在对象库中找到“侦探Jack”,然后点击它(推荐)。

3种方式中有两种是推荐使用方法。如果没有打开对象库,那就直接点击工具栏中的图标,如果对象库已被打开,那么就可以点击里面的图标(前面的内容中已提到过,点击对象库中的Spy 图标一样能调用它),做到灵活应用!细心的读者会问,为什么不支持快捷键?这个问题请咨询HP,至少目前暂时还没有快捷键。那么接下来,有请我们的“侦探Jack”,如图1-102所示。

如图1-102所示,已经见到了“Jack先生”的庐山真面目,那么接下来作者用它探测一个对象,然后对这个界面做一些说明(如何探测先不讲,后面就讲。另外,本说明只针对新人,已经会的朋友请体谅下作者要照顾到每一位读者,暂时跳过即可),被探测的对象是百度的搜索框。那么就让新人和作者一起来看界面说明图,如图1-103所示。

界面详细说明。

1.探测手指

点击该手指后会出现一个白色的手指,就和添加对象一样,作用就是选择需要探测的对象,在下一个小节中,作者会扩充一个知识点“捕获对象时的模式切换”。

2.Keep Object Spy on top while spying

探测时保持探测器置顶,这个就看个人习惯了,默认是勾选上的,也就是总是保持置顶的,如果不习惯这种方式,取消勾选就可以了,在这里还是推荐大家采用默认的形式。

3.显示对象的区域

在使用探测手指后,这块显示区域会显示Object Spy 探测到的对象及其父对象、祖父对象。默认是停格在被探测的对象上,如果需要查看它的父对象或祖父对象,只需点击即可。在这里能看到“百度搜索框”被探测到了,它就是“WebEdit:wd”。

4.Native Properties 和Identification Properties的切换

这是一个重点,也是学习Spy探测器最难的地方!这里所牵涉的内容不只包括本小节,还包括本小节以外的另外几个小节。在这里先大致介绍一下,以后还会多次碰到。首先,作者在这里做一下翻译工作,Native Properties=本地的属性,Identification Properties=鉴别属性,这两个名词一定看不懂。让作者来替广大新人读者解惑,本地属性就把它看作一个对象控件的自身接口的属性,而鉴别属性它是QTP默认为该对象控件封装的属性。本地的属性相当多,是封装属性的数倍!下面图1-104所示是切换到封装属性的情况,显示的都是“百度搜索框”的封装属性:

图1-102
图1-103

图1-106就是“百度搜索框”的一些封装的属性。什么叫封装?这个在这里就不多解释了,因为和本书无关,不过在这里可以告诉你,QTP,把“百度搜索框”封装成一个 WebEdit 控件,依据在哪?因为 Class Name =WebEdit (位置在图 1-104 中已标注)。Class Name 就是“百度搜索框”众多封装属性中的一个,读者可以重新选择到本地属性里去看看有没有Class Name,答案是没有!至于这些封装属性是怎么来的呢?答案是 QTP自己给封装好的。所以,关于这些封装属性的秘密,在下一章节中会讲到,敬请期待吧!

图1-104

言归正传。两种属性都是在实际的运用中经常会被用到的,调用不同的属性方法的形式也是不同的,两个概念上的介绍基本就到这里了。

后者是Identification Properties,以后会牵涉到对象库编程中的两个重大概念Test Objects(测试对象,TO)和Run-time Objects(运行时对象,RO),在为TO或RO进行编码的时候使用的就是QTP自己封装的这些对象属性。关于前者,也就是NativeProperties有其独特的调用方法。

5.Properties和Operations的切换

这里以切换选项卡的形式来查看对象的属性或查看关于该对象控件的操作的一些方法,默认选项卡是查看对象属性的。

6.对象属性&对象操作的详细表

本条和第5条是关联的,在这个区域能查询到对象的属性(包括本地的属性和鉴别属性)及其属性值或对象控件的一些方法,在图1-104中,我们可以看到对象的具体属性显示效果,那么接下来,把选项卡切换到“对象操作”效率效果,如图1-105所示。

在如图1-105中,可以查看到关于“百度搜索框”的一些可执行的操作及其方法,如CheckProperty、Click、Drop、ChildObjects及Exist等。

图1-105

7.文字显示区域

别小看这一块小小的区域,在实际项目中有实际的用处的,现举两个例子,先来看一下两张图(图1-106和图1-107)。

图1-106
图1-107

首先需要说明一下,在图 1-106 上鼠标箭头停格在 default value 这个属性上并点击,而图1-107则是停格在属性abs_x的值606上并点击,由于鼠标箭头无法被截在图中,所以只能在图中标记。

为什么说这个小小的区域很实用呢?第一个例子大家请看图 1-106,假设需要把 default value这个属性写到脚本的某行中去。那么此时有两种办法,第一种就是手写,一个一个字母的拼写,显然这种方法效率比较低,而且容易拼写错。所以推荐第二种方法,就是去点击表中的default value,点击后,在文字显示区域就会显示default value了,然后再复制、粘贴到脚本中,这样效率就大大提高而且绝对不会出错了。这个default value的例子还是比较经典的,请注意当中是有一个空格的,用这种的话就保证不会漏掉这个空格了。

然后看一下第二个例子,在这里不光可以点击“属性”,还可以点击“属性的值”,同样可以出现在文字显示区域中,比如图1-107中的606。除此之外,Operations选项卡下的内容同样能够点击、显示,只不过Operations选项卡下的内容只是看看就行了,是没有实际性用途的。

8.具体描述区域

这个区域中会显示一些QTP自带的描述信息。细心的读者应该会发现,Properties选项卡下这块区域是没有什么描述信息的,这说明HP公司并没有给各类属性添加描述。但是在切换到Operations选项卡后,可以发现HP公司给所有QTP自行封装的方法进行了描述,比如Click方法(图1-108),而自身接口的一些操作方法都是没有描述的,同样如Click方法(图1-109)。

图1-108
图1-109

这个知识点大家只需要了解即可,即使QTP自带的封装方法有一些描述,也没有必要去看,因为我们有“F1”这个好老师。

1.5.5.2 捕获对象时的模式切换

在讲解对象库功能之一“6.添加对象”的时候,作者分享了“小提示 9”,读者可以重新翻回到那部分内容。当时提出了一个问题“假设在一个页面上,添加对象后需要切换到另一个Web页面添加另一个对象怎么办?”,最后作者给出了最好的解决方案“在添加对象时, QTP 提供了捕捉模式切换功能”。但是作者并没有继续深入下去,因为添加对象时的模式切换是和本小节要讲到的Object Spy 捕捉对象的模式切换是一致的,现在,可以好好学习一下这个技巧了,这个知识点在今后的实际项目运用中经常会被使用到。

作者先举一个简单的例子,还是借用“百度”为例,当我们打开百度进入到百度首页时,会发现有个搜索框,这个搜索框是有讲究的,它支持AJAX技术,直白点说也就是模糊匹配下拉框功能,那么在这里我们将通过这个功能来进入本小节的主题。

实验开始了,在搜索框中输入“QTP”,可以看到此搜索框下面会自动出现一些模糊匹配“QTP”的关键词,如图1-110所示。

图1-110

假设需要在这功能上做自动化测试,首先需要抓取到这些对象(模糊匹配出来的关键词)。那让我们试着使用“侦探 Jack”去抓取它们!但是,我们会发现在抓取的时候事情出现了。你会发现“侦探Jack”根本无法抓取到图中的这些模糊匹配出来的对象,当点击探测手指以后就相当于切换了窗口,再切回来的话模糊匹配下拉框就必定会消失,这样就导致根本无法正常捕捉到这些需要获取的对象……这块功能的自动化测试就无法进行下去吗?当然不是!其实这块功能的自动化测试是非常简单的,问题就出在无法捕获到这些模糊匹配的对象控件。为了解决这个问题。那么在这里为读者介绍的模式切换就起到了决定性的作用,我们完全可以不需要切换百度窗口而直接获取到模糊匹配下拉框里的对象,这就是模式切换的优势,接下来,会详细讲解本小节的主题——捕获对象时的模式切换(当然也包括了添加对象时)。

通常使用过QTP的读者都会发现,当使用Spy或者对象库捕获对象时,一旦点击白色手指后就只能抓取对象而无法进行其他任何操作。但其实当在点击了白色手指之后,仍然可以通过两种模式切换操作,使得切换后可以停止对控件的抓取,并还可以对被测对象进行操作。那么,看一下是哪两种模式。

半操作模式——CTRL键 支持点击。

全操作模式——CTRL+ALT键 支持点击和键盘输入。

1.半操作模式详解

首先进入百度首页,当使用Spy并点击白色手指后,可以看到鼠标光标是手指的状态,此时也就是捕获对象的状态。在这个时侯是不可以做任何操作的,只能抓取想要的对象,而当按住CTRL键并保持不放开,就可以做点击动作了,如同正常操作网页,也包括拉动滚动条等。与此同时,鼠标光标也会从“小手指”变回原来的鼠标箭头,当放开CTRL键时,可以看到鼠标光标又会从箭头恢复到“小手指”,也就等于恢复到抓取对象的模式。

2.全操作模式详解

全操作模式就是支持任何操作,包括点击和键盘输入。当处在抓取对象模式的情况下按住CTRL键不放,然后再按下ALT键,紧接着先松开CTRL键再松开ALT键,这样就已经成功切换到全操作模式了。假设在此模式下在百度搜索框中进行输入操作,输入“quicktest”(图1-111),在输入后百度搜索框会弹出模糊匹配下拉框,这个时候可以通过点击CTRL键,然后松开从而达到切换回抓取对象模式的目的,此时模糊匹配下拉框也就不会消失了,这样就能够对模糊匹配下拉框对象控件进行“抓取”,也就成功解决了之前无法抓取到该对象的难题(见图1-112)。有了模式切换,就算再“狡猾”的对象控件也照样会被一网打尽。

图1-111
图1-112

小技巧

当在使用Spy抓取对象时,如果遇到需要抓取的对象恰好被Spy窗口挡住的情况(图1-113),可以拖动Spy使其不会将需要添加的对象挡住(图1-114)。

图1-113
图1-114

整个Object Spy操作运用就介绍到这里了,对于自动化测试工程师来说,“侦探Jack”起着至关重要的作用,往往需要去探测一些对象控件的属性并利用它们,这就全要靠我们今天认识的这位“新朋友”了。特别是新人,他们往往对对象控件的“习性”不够熟悉,所以更加需要依赖于Spy,直到对每个对象都非常熟悉以后,可以逐步摆脱Spy来节省时间。

 

1.5.6 对象库的最高指挥官(Object Repository Manager)

1.5.6.1 使用公共对象库更有利于项目管理

对于使用 QTP 的自动化测试项目来说,其对象库的管理在整个自动化测试过程中占有非常重要的地位。特别是对于一个大型的应用系统,往往界面上的对象多而杂,所以拥有一个统一、规范、直观、有序的对象库将非常有利于脚本的快速开发以及团队成员间的协作。在前面的小节中已经深入介绍了Object Repository,不过这只能说已经掌握了单兵作战的技巧,在真实的自动化测试项目运用中,我们需要的是整个团队的协作,只有这样自动化测试项目最终才能成功。如果选择对象库编程来完成所在的项目,那么如何管理好对象库将是一门很大的学问和最当务之急要研究、探讨的事情。

有幸的是,QTP提供了一套管理对象库的功能,由此也就产生了公共对象库的概念。那么,什么叫公共对象库呢?举个最简单的例子,假设系统中有3个模块,分别由3名自动化测试工程师负责,此3人在完成自己模块的脚本开发后,开始进行脚本联调,但是他们发现自己模块的脚本单独运行都非常完美而却在集成完毕以后发生了致命的错误,没有一个组合后的业务脚本能够顺利的通过。最后他们发现,导致如此的原因是因为,他们没有一个统一的对象库,比如有一个公共对象Browser(“browser”),3个模块都具备这么一个对象,但是3名工程师分别把它写成了Browser(“browser1”)、Browser(“browser2”)、Browser(“browser3”),对象的命名规范都没有统一,那最终集成到一起以后怎么可能没有问题呢?要想防止类似的问题发生,就必须管理好对象库,将凌乱而琐碎的对象进行统一管理,并集成到一个对象库中,所有工程师只在这一个对象库上进行脚本开发工作,因此也就产生了公共对象库这个名词!当然,作者也并不是说必须所有的对象全部集合在一个对象库中,但是至少(再次强调“至少”这两个字)模块间共有的对象必须提炼出来并统一命名,然后封装成一个供所有团队成员共享的公共对象库。这个公共对象库是不能随意变更的,必须有专人进行严格控制及维护,这个在本书的第一章中就已经讲过。另外,关于如何调用公共对象库,请读者复习“1.5.4 对象库基本操作”,这个小节中的第10点“Associate Repositories”,在这里就不再对这些知识点做重复性的阐述了。现在去认识对象库的最高指挥官Object Repository Manager吧。

首先,召唤Object Repository Manager的方法不像召唤Object Spy 那样的多,既没有快捷键,也没有什么直接可以点击的图标,唯一的入口就是。

QTP 上方菜单栏→Resources→Object Repository Manager。

点击进入后,界面效果如图1-115所示。

从图1-115中可以看到Object Repository Manager中的很多可用功能和前面已经介绍过的Object Repository中的完全是同一个功能,在图1-115 中,作者只是特别标注了个别几个。这些既然前面都已经介绍过,在这里就略过了。接下来,结合一个实例来介绍 Enable Editing这个功能(图1-115中已标注位置)以及整个对象库管理的大致操作流程。

Object Repository Manager的实例1。

Step1,依次选择File→Open→link.tsr。

打开之前使用过的素材<一个对象库文件>,打开后的效果如图1-116所示。

图1-115
图1-116

在1-116 图中,读者需要注意到3 处地方,Read only、Add 按钮灰色以及所有对象的灰色,由此可以得出结论:原来在Object Repository Manager 中打开一个对象库文件后是不能进行编辑修改的,也不可以添加新的对象进来,只可以单纯地“看”!那这样的话,这个对象库管理机制还有什么实质意义呢?难道想要添加或者修改亦或者删除一些对象都不行吗?

当然不是!这只是默认的一个情况,在Object Repository Manager中提供了一个按钮,它就是 Enable Editing,点击它以后,就可以随心所欲地进行各种操作了。那我们来点击它并看一下点击后的效果,如图1-117所示。

图1-117

如图1-117 所示,这个Enable Editing 按钮功能重新给我们带来了“光明”!

当“管理”好对象以后,就可以将战果保存下来了,这个就简单了,在File菜单下New、Open、Save、SaveAs 等一些功能。

Step2,依次选择File→Save(也可以使用快捷键Ctrl+S)。

至此,对象库管理的一个大致流程就完成了,当下次再打开link.tsr文件后就会发现对象库中的对象已经被优化过了(新增、修改、删除、合并等)。当然,你不想去改变 link.tsr 文件的话,操作Save As保存就行了,将当前对象库以其他命名保存。所以,对象库文件除了可以在Object Repository 中通过导出生成,在这里也同样可以生成,只是存在着一些区别,一个叫Export、另一个叫SaveAs,仅此而已。

1.5.6.2 对象库的对比与合并

既然是在介绍Object Repository Manager,那就不得不提起它的两个“王牌级”的辅助工具:一个“Object Repository Comparison Tool”,另一个“Object Repository Merge Tool”。这两张王牌是内嵌在 Object Repository Manager 中的,使用它们的方式也很简单,分别是选择Tools→Object Repository Comparison Tool,以及选择Tools→Object Repository Merge Tool,不过千万要记住这里的“Tools”是对象库管理工具里面的那个。另外,这两个辅助工具和对象库管理工具一样,打开以后都是以独立的窗口显示的,和 QTP 程序窗口是分开的,好象它们都是一个个单独的小程序,让我们来看一下全部打开以后的效果,如图1-118所示。

图1-118

那么接下来,将使用两个实例来介绍这两个辅助工具的用法与作用,以及操作它们的一个大致流程。先来介绍Object Repository Comparison Tool,一起来看下面这个实例。

Object Repository Manager的实例2。

Step1,依次选择Tools→Object Repository Comparison Tool。

打开对象库对比工具,进入后的界面如图1-119所示。

图1-119

如图1-119 所示,打开这个工具以后会自动弹出一个New Comparison 对话框,然后继续进行下一步操作。

Step2,选择First file和Second file(所选文件如图1-120 所示),然后点击OK 按钮。

图1-120

再将两个文件分别选择完毕并点击OK以后,会进入图1-121所示的界面。

图1-121

如图1-121中所示,点击OK按钮后立即弹出了一个Statistics对话框,接下来就要进入下一步了。

Step3,分析统计数字以及查看两个被比较的对象库之间的差异。

首先,需要分析统计出来的数据,Statistics 对话框里所列的数据是相当直观的,如图1-122所示。

图1-122

通过这些统计数据可以让我们能更快捷有效地查看对象库之间的差异,图 1-123 显示的就是本实例中出现的两个对象库文件之间的差异。

如图 1-123 所示,图形化的差异标识显得非常地清晰和直观,并且情况完全和统计对话框中的数据吻合。由此可见,Object Repository Comparison Tool的确是一个非常实用的辅助工具。

图1-123

在自动化测试项目中,对象库管理人员在做对象库维护时,如果能善加利用这些小工具就一定能事半功倍,当然这只是第一步,目前只是停留在一个分析与确定的阶段,还需要一个步骤,完成对象库的维护工作才算最终完成。这个后续的步骤是什么?那就是对象库合并。读者又要问了,如何才能把不同对象库中的对象合并到同一个对象库中呢?接下来,作者要推介给读者的就是一个对象库合并工具Object Repository Merge Tool,继续看第二个实例,在这个实例中作者同样会做一个流程的操作。

Object Repository Manager的实例3。

Step1,依次选择Tools→Object Repository MergeTool。

打开对象库合并工具,进入后的界面如图1-124所示。

图1-124

同样,打开这个合并工具后也会自动弹出一个对话框,只不过它换了个名字叫New Merge而已,然后继续进行下一步操作。

Step2,选择Primary file和Secondary File,然后点击OK 按钮,如图1-125所示。

图1-125

如图1-125所示,我们仍然使用之前的两个对象库文件来完成本次实例,再将两个文件分别选择完毕并点击OK以后会进入图1-126所示的界面。

图1-126

如图1-126所示,点击OK后同样也是弹出一个Statistics对话框,里面包含了关键数据让我们可以一目了然地去掌握一些信息,然后在整个界面的左侧会显示初步合并后的结果(初步合并是自动且默认的),让我们来看一下(如图1-127所示)。

如图1-127所示,在对象的左侧出现了一些数字而有的对象却没有,这里的“1”代表第一个对象库里的对象,而“2”则代表第二个对象库里的对象,那些没有数字的则说明它们是两个对象库共有的对象(共有的对象是要所有属性完全一致才算)。那么接下来再来看一下整个界面的右侧部分,如图1-128所示。

图1-127
图1-128

界面我们已经看到了,图例中也做了相应的说明,需要注意的是,当前两个对象库中的对象没有冲突,所以合并的工作就由系统代劳了,不用再手工去设置,也就是因为这个原因,下面的Previous Conflict和Next Conflict 两个按钮灰色。由于没有冲突,所以,到这一步对象库合并工作就算结束了,左侧的初步显示的合并结果也将成为最后的结果,最后只需要记得将Statistics对话框关闭掉,并把“战果”保存下来即可。

以上是没有冲突的一个情况,接下来继续再看如果两个对象库之间存在冲突,我们的Merge工具如何来应对,重复的过程就跳过了,直接来看冲突结果,如图1-129所示。

从图1-129 中可以看到,Merge Tool 会准确标记出那些需要合并但是又有冲突的对象的位置。那么此时此刻,需要继续做些什么呢?那就是给出一个解决方案,比如在两个冲突的对象间到底保留哪个对象等。先看一张图例,如图1-130所示。

图1-129
图1-130

如图1-130 所示,Resolution Options区域就是Merge Tool 的“杀手锏”,上半部分会告知用户一些所需的信息,而下半部分则提供了3种不同的解决方案(见图1-130)。默认选择最下面的Keep both objects,也就是因为这个选项才会有前面那一张初步合并的结果图,保留了第二个对象库中的“百度一下,你就知道”Browser 对象,但又为了使其不冲突,所以自动更名为“百度一下,你就知道_1”。至于其他两种方式就不多做介绍了,意思已经相当明确了,读者可以自行将各种解决方案都体验一把。最后,只需要和前面一样,将“战果”保存下来就行。

到此,整个Object Repository Manager 小节就介绍完了,它当之无愧的是对象库的最高“指挥官”。同时,作者再次重申:管理对象库就好比管理你的程序,是一项重点工作,必须有统一的命名规则和标准等。在做项目时,如果能有一个优秀的公共对象库供自动化测试工程师调用,那么工作效率势必会翻倍!

 

1.5.7 总结

本章节基本上是围绕 QTP 工具本身的功能在做介绍,同时作者也分享了不少额外补充内容,比如说想要做好自动化测试项目,那么管理好对象库则是非常关键的一个环节等一些思想及实际经验。所以,读者不仅仅可以在本章节中学会如何去使用对象库相关的功能,更重要的是读者可以逐步学会,如何将一些好的思想经验和实际的功能操作去相结合。需要注意的是,本章节中介绍的功能都是对象库中最最重要的那些,所以读者务必要掌握操作技巧并能熟练运用。

 

知识点巩固和举一反三练习

一、请在本地对象库中任意添加一些对象并将该对象库导出。

要求 1:规范命名添加后的对象,养成好习惯。

要求 2:对象添加完毕后导出至D 盘目录下并命名为local.tsr。

二、将“练习一”中已完成的local.tsr对象库转变成可供多人调用的公共对象库。

要求 1:在对象库管理工具中打开local.tsr文件并任意新增一些对象(即维护对象库)。

要求 2:维护完毕后以另存为的方式将维护后的对象库保存至 D 盘目录下并命名为public.tsr,使其成为一个公共对象库。

要求 3:调用公共对象库。

 

1.6 对象库(下)之进阶编程篇

阶段要点

• 掌握手写代码的3 种方式。

• 明确测试对象(TO)与运行时对象(RO)的区别。

• 4 种操作对象封装属性的方法。

• 你也可以是一名魔术师、黑客。

• 几种常见的QTP 无法识别或识别错误的原因。

 

1.6.1 引言

在对象库上篇这个章节中,相信读者已经对对象库的使用以及其他各个方面有了一个全面的了解。那么从现在开始,作者将引领读者开始基于对象库编程的学习,从而掌握对象库编程的知识与技巧。读者如果觉得在对象库上篇中还有不能够完全掌握的地方,建议重新学习直到完全掌握为止,因为只有打好了上篇所介绍的基础,才能学习好下篇的知识,真正做到融会贯通。

在前面的章节“1.4 认真并请远离QTP的脚本录制模式”中,作者也已经提到过在QTP自动化测试中绝对不只是单纯的录制与回放,因为只要稍微复杂点的业务,录制模式就不能满足我们的需求了。那么,要想完成自动化测试业务流,就必须依仗QTP的编程模式,举个例子,就比如多个脚本间的数据中转,如果没掌握QTP的编程知识,那一定就没有办法实现。在1.4章节中,作者已经展示过了QTP的代码片段,但并没有深入去介绍到底如何去手写代码,因为这些内容都是本章节的重点。接下来就要开始逐步地详细介绍QTP的第一种编程模式“对象库编程”了,这种编程模式同样也是作者最推崇的一种模式,因为它是QTP的一个特色和亮点。本章节也可以说是到目前为止最难学习的一个章节,包含的内容也很多,包括对象库的编程技巧、编程知识、编程原理等。不过,作者相信在学习完本章节以后,读者的 QTP水平一定会有一个明显的飞跃。当然,条件是读者必须深入掌握本章节的所有内容,并能够举一反三。如果对象库编程没有学好,那将会成为读者今后应用QTP自动化测试技术的绊脚石。

 

1.6.2 基于Expert View的对象库编程必备知识

1.6.2.1 手写代码的3 种方式

在QTP的对象库编程中,存在着3种编写代码的方式,依次分别是:步骤生成器、Complete Word、对象拖动生成。接下来,作者就依次介绍这些手工生成代码的方式。

第一种:步骤生成器方式。

先要介绍的是步骤生成器方式,这种方式可以说是QTP的一个“元老”,在QTP一出现就具备了。严格来说,它应该算是QTP的一种功能,接下来就让我们一起动手完成一系列的实例,从而掌握这种编程方式。

既然是一种功能,那么就首先来看一下它所处的地理位置,以及如何去访问到这个功能。

依次选择QTP上方菜单栏→Insert→StepGenerator。

操作快捷键F7。

现在随意使用一种手段去使用它,并来认识它,如图1-131所示。

图1-131

如图1-131所示,可以看到这就是步骤生成器的一个界面。在Category中有3个下拉选项(在图中已经展示出来了),这3个选项就分别代表了步骤生成器可以生成的3种不同类别的代码。

小提示

在QTP的Expert View编程中,一行代码就是一个步骤,所以,生成了一行代码也就等于生成了一个步骤。

接下来就逐一生成不同类别的步骤,QTP的“F7”一共可以生成3个类别的代码,所以在这里就划分成3个实例进行操作演示并同步讲解。

实例1:Test Objects。

预备工作:添加一些对象进对象库,事先已经添加好了,如图1-132所示。

如图1-132所示,我们看到对象库里存在一些对象了,那么,接下来需要完成这样一个任务,就是生成一句点击“百度一下”按钮的代码。

Step1,选中Test Objects下拉选项,选择完毕后,如图1-133所示。

图1-132
图1-133

如图1-133所示,我们可以看到,在选中Test Objects这个分类以后,它下面的那个Object下拉框默认显示了一个对象,这个对象就是对象库中的那个父对象。然后再来看Object下拉框的下面,它是一个Operation下拉框,顾名思义就是,这个下拉框可以选择各种不同的操作,不过需要注意的是,Operation下拉框中的可选操作都是基于当前所选择的对象,当前所选对象不支持的操作是选择不到的。我们可以看到,当前默认选择的是Sync操作,这个不用去管它,是系统默认的,不用去深究。接着在下面有一个Arguments的区域,在这里会显示所选操作的一些参数,当前在图1-133中这块区域没有任何东西,是因为Sync这个操作方法没有参数可设置。再接着下面是一个 Return value 的勾选框,如果当前的对象操作可以有返回值的话,就可以勾选了,并且还能在后面的文本框中输入返回值的名称。最下面就是一个步骤生成预览的区域,这个就不多解释了。如果生成一个步骤以后,还要继续生成其他后续步骤,则勾选上Insert another step,这样在点击了OK 按钮以后,“F7”窗口就不会关闭了,可以继续生成下一个步骤代码。好了,也借此机会把这个界面上的一些功能大致介绍了一下,让读者有个了解,在接下来的操作中就不再重复介绍了。

那么继续回到主题,显然现在默认所选的对象不是我们需要的,需要的是生成一句对“百度一下”进行操作的代码,那么此时该怎么办呢?让我们来看下一步。

Step2,点击 Object 下拉框右边的“方块+箭头”按钮(在图 1-133 中),在点击以后会出现一个Select Object for Step的界面,如图1-134所示。

如图1-134所示,可以看到在Select Object for Step这个界面中可以进行对象的选择,除此以外,还包括了一些其他的功能,比如对象查找、从程序指定对象等,这些功能不是重点,就不多做介绍了。那么,我们就选择“百度一下”对象,然后点击OK按钮,点击后如图1-135所示。

图1-134
图1-135

如图1-135所示,现在可以看到Object下拉框中已经变成了“百度一下”这个Button对象,并且Operation下拉框也随之变成了Button对象下的一些操作方法,默认是Click(恰好是需要的操作方法)。

Step3,进行后续设置。这一步就很简单了,我们就拿“百度一下”这个 Button 控件为例,可以从图1-135中看到Button控件的Click方法有3个参数,其中参数x和参数y是可以设一个值的(如果需要的话),参数BUTTON由于不能设置具体的值,所以QTP显示了<NoValue>。那么接下来就试着设置一下参数x和参数y吧,在设置之前大家请注意步骤生成预览区域的代码,目前是:“Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Click”,等设置了参数以后再来看看步骤生成代码区域。

Step4,设置x =97、y = 120。分别点击x 与y的Value对应列,点击后的效果如图1-136所示。

图1-136

从图 1-136 中可以看到,x 的值已经可以设置了,不过要注意的是,准备输入的值需要与Type类型相关,Integer类型的输入值当然不可以是字符串类型,反之亦然。在继续输入Value之前作者还要介绍一个小功能点,它就是<#>按钮(图1-136中0的右边),这个按钮的作用是参数化,可以在这里将Value 参数化,然后在QTP 的Data Table 里设置各种需要的测试数据。来看一下它的界面,首先点击一下<#>按钮,点击后的效果如图1-137所示。

如图1-137所示,选择Parameter后就可以将参数进行参数化设置了,并且可以选择参数化数据的位置(Global sheet或Current action sheet)。另外,Parameter这个下拉框的其他一些选项在这里就不多做介绍了。读者目前只需要知道步骤生成器里也可以将数据参数化即可,关于QTP 的DataT able 会在后面的一个章节独立介绍。

回到正题,待x和y都设置好以后,再来看一下步骤生成预览区域的代码,看看是否起了变化,如图1-138所示。

图1-137
图1-138

如图1-138所示,在Click方法后面多出了两个参数,就是我们设置的x和y,当然,对于一个Button控件来说,这些参数其实可有可无,除非是一些很特殊的情况,一般情况下都是不用去设置的,作者在这里只是做个演示。

第一种手写代码的方式就写到这里,这个方式在QTP 8.x的时候还是经常被使用到的,接下来继续看一下其他代码生成方式。

第二种:Complete Word 方式。

相信做过开发或者写过Java代码的读者都应该对Complete Word这个名词不陌生?它就是开发脚本过程中的催化剂。有了它就可以不用去死记硬背一些代码;有了它就不会再因为代码不小心编译错误而烦恼,比如最常见的拼写错误;有了它我们的编程速度会明显提升。因此,Complete Word 不但对开发程序相当重要,对测试脚本的设计也同样起着至关紧要的作用!下面就来介绍如何在QTP 中实现Complete Word。

首先打开QTP 并依次点击上方菜单栏下的Edit→Advanced,在找到Complete Word 后,读者会发现一个很尴尬的事情,就是QTP 设定的Complete Word 正是平常一直使用的切换中、英文的快捷键Ctrl+Space,而由于快捷键Ctrl+Space被优先认定为中、英文切换组合键,所以会导致QTP 的Complete Word 无效。

解决步骤。

(1)右键单击语言栏,点击设置。

(2)点击键设置,选择输入法/非输入法切换。

(3)点击更改按键顺序。

(4)如图1-139所示的选择,然后点击确定。

图1-139

解决这个问题是很简单的,只不过如果读者平时习惯使用Ctrl+Space来中、英文切换,那为了使用QTP只能不用Ctrl+Space切换中、英文了。

在完成了以上4个步骤之后,就可以在Expert View 中使用快捷键 Ctrl+Space 来调出 Complete Word了,如图1-140所示。

接下来,来做一个实例,假设当前的ExpertView中有以下两个函数:

Function test_hello_world_one

msgbox "test1"

End Function

Function test_hello_world_two

msgbox "test2"

End Function

现在,需要调用这两个函数,那么就可以直接使用Complete Word 来效率地完成了,如图1-141所示。

图1-140
图1-141

是不是非常方便呢?再举一个例子,假设现在要使用Complete Word生成下面这段代码:

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "QTP自动化测试技术领航"

在这里,作者形象地写出生成这句代码的整个过程,使得读者可以掌握快速写代码的技巧,其实非常简单,读者看了以后就能学会,过程如下所示。

Step1,敲击键盘Ctrl+Space,然后再敲击键盘上的字母B,此时,QTP 会自动地找到以B 开头的所有Complete Word(见图1-142),接着敲击回车,此时Browser 这个Word就会输入到ExpertView里,然后再敲击“左括号”,完成目前所有步骤后的效果见图1-143 所示。

图1-142
图1-143

小提示

QTP中所有的代码编译都是基于英文输入法的,如果是中文输入法,检查语法的时候会显示错误。如果Step1中输入的是中文输入法下的左括号,那Browser的具体对象是不会跳出来的。

Step2,从图1-143 中可以看到,在敲击了左括号以后,QTP 会自动将Browser 控件的具体对象补全,(补充:这里QTP所补的具体对象一定要是对象库中存在的,换句话说,只有对象库编程才支持这种方法,另外,如果当前对象库中假设有两个Browser或其他任意对象(如Page、WebButton、WebEdit等所有),那么QTP会给出一个选择框来选择当前需要的对象,见图1-144),然后输入右括号来完成对象的描述,在这里描述的是Browser对象。

Step3,完成了Browser对象后,现在需要调用它的子对象Page 对象,此时只要敲击键盘上的“点”以后,就会弹出一个选择框,里面包含了Browser对象的所有方法、属性和子对象,然后敲击字母P使其直接定位到以P开头的Word,并最终定格在Page这个子对象的位置上,如图1-145所示。

图1-144
图1-145

接着就和Step2中一样了,使用左右括号来完成Page对象的描述。再以同样的方法完成WebEdit对象的编译后,就彻底完成了对象定位,如图1-146所示。

图1-146

Step4,完成最终对象定位以后,还没有真正的结束,最后一步就是给予最终定位到的对象一个“操作动作”,也就是常说的方法。在此,仍然需要敲击“点”来调用WebEdit对象下的各种方法或属性,在这里,选择的是实例要求中的 Set 方法,待所需的方法选择完成,最后一步是设置这个方法的参数值,这样,整个流程就完成了,如图1-147所示。

图1-147

总结:Complete Word 是目前QTP 编写代码过程中使用率最高的一种方式,一旦操作熟悉以后,可以大大提高QTP自动化测试的工作效率。

第三种:对象拖动生成方式。

最后,作者要介绍的一种方式是把对象拖动到Expert View里来快速生成代码,这种方式只支持QTP10.0以上的版本,在之前的早期版本中没有此项功能,这项功能的出现也抢占了一部分使用第二种方式的市场份额。先来看一下这个新功能所在的界面,如图1-148所示。

图1-148

如图1-148所示,可以看到所有的测试对象都出现在一个叫Available Keywords的窗口中,拖动对象生成代码必须也只能在这个窗口进行,其他位置(比如对象库)里就不支持对象拖动。在这个窗口中不光显示所有的测试对象,还会显示所有的Functions,包括外部调用的和脚本内部本身的Function,同时也可以看到右键单击某个对象后可以点击OpenResource,可以通过这样一种方式来进入对象库,并直接定位到所选的对象在对象库中的位置,可以说这个窗口是非常实用的一个功能。

那么接下来就介绍拖动生成代码的方法和一些必知的知识。拖动操作其实是非常方便的,只需要在窗口中定位到所需要的控件,然后Drag&Drop到Expert View中即可,如图1-149所示。

图1-149

如图1-149所示,一句代码就自动生成了,生成最终对象WebEdit(“wd”)的同时也默认给出了一个最基本的方法 Set,方法后的参数则需要自己填写,并且也可以看到,在生成完毕后,光标自动进到了第二行。在这里,读者需要知道,我们不仅仅可以定位最终对象,也可以对一些父对象进行拖动并生成代码,现在拖动Page(“百度一下,你就知道”)这个对象来试试看,如图1-150所示。

图1-150

如图1-150所示,只用一句代码就生成了,这次生成的是Page连同其父对象,并默认给出了一个Sync方法(不用关心为什么默认会生成这个方法),如果需要使用其他方法,把.Sync删除,重新“点”一下即可。

总结:

随着代码拖动生成这个功能的实现,开发 QTP 脚本更加快捷了,当然这里有一个小小的不足就是会默认生成一个方法,这个方法往往不是想要的,只能手工去删除然后重新“点”出新方法,这样会浪费一点时间,但总体来说,代码拖动生成是目前为止最高效的一种方法,基本上使用QTP10.0以上版本的自动化测试工程师都会选择这种方式,也是作者强烈推荐的!当然,这个功能只能支持基于对象库的编程。

1.6.2.2 其他补充知识点

在上一个小节里,已经介绍了快速编译QTP脚本代码的3种方式,在本小节中,作者将补充一些QTP编码过程中的小技巧。

1.QTP IDE 中的垂直分割选取

相信读者应该都知道在大多数开发的IDE中都会有垂直分割选取,它可以在文本中选取一个特定的垂直柱,并可以进行多行同时输入代码,如图1-151所示。

图1-151

当然,QTP的IDE也不例外,同样也可以使用此功能,可以省去很多不必要的操作,让我们来做一个实例。

Step1,新建一个Test,输入如图1-152 所示的代码。

图1-152

Step2,现在可以使用垂直选取的方法轻松地对多行代码进行同时更改,首先,要选取到“垂直柱”。选取方法:在左上角点击鼠标左键往右拉一定距离不放手,与此同时,再点击一下鼠标右键,然后,就可以轻松地进行垂直段的选择了,如图1-153所示。

图1-153

Step3,选取垂直柱之后,可以输入想要更改的代码,比如这里输入“dim”,QTP 就会同时对多行进行输入并覆盖原先的Public,如图1-154所示。

如图1-154所示,已经批量修改完毕了,同时这个小小的功能也就介绍完了,大家可别小看它,有时候往往能够帮助我们节省很多时间,提升工作效率。

图1-154

2.代码换行符

假设现在有这样一句代码:Browser("51Testing 软件测试网-中国软件测试人的精神家园").Page("51Testing 软件测试网-中国软件测试人的精神家园").Image("51Testing 软件测试网").Click,这句代码非常长,当前的Expert View无法完全显示这行代码,只能看到一半,这样的话看代码就会显得相当不方便,需要拖动滚动轴才能看到后面的代码。

如何解决?QTP 提供了一个代码换行符号,它就是“_”符号。有了它,就可以将一句代码切分成好多行,缩短代码的长度,可以清晰地浏览代码,可以这样切分,比如:

'#1

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园")._

Image("51Testing软件测试网").Click

'#2

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园").Image("51Testing软件测试网").Click

'#3

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园")._

Image("51Testing软件测试网")._

Click

但是,我们不能这样切分,比如:

'#1 – “点”放在换行符号后面

Browser("51Testing软件测试网-中国软件测试人的精神家园")_.

Page("51Testing软件测试网-中国软件测试人的精神家园")_.

Image("51Testing软件测试网").Click

'#2 – 换行符号的插入导致描述一个对象(Image)的代码被分割成2段

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园").Image("51Testing _软件测试网").Click

'#3 – 在结束时不能使用换行符号

Browser("51Testing软件测试网-中国软件测试人的精神家园")._

Page("51Testing软件测试网-中国软件测试人的精神家园")._

Image("51Testing软件测试网").Click_

换行符号对于代码的可读性等方面起着重要的作用。其实,细心的读者应该已经在前面的章节中看到过这个“_”符号了,它将会是今后经常用到的工具

3.Alt+G快捷键

位置:依次选择QTP 上方菜单栏→Edit→Advanced→Go to Function Definition。

这是一个比较有用的快捷键,假设目前的脚本有1000行代码,代码中有很多Function,此时如果有了这个快捷键,就能够将光标定位到调用Function的这行代码,然后按下Alt+G,快速跳转定位到该调用的Function在脚本中的位置,使得能够相当快速地查看到Function里的功能,演示如下:

'假设是第20行代码

Call func_test01 '调用func_test01函数 –光标定格在本行,PRESS "Alt+G"

'假设这个函数从第850行开始

Function func_test01 'Alt+G后,光标会直接停留在此行,瞬间从第20行跳到850行

Msgbox "test01"

End Function

Alt+G功能介绍完了,读者需注意的是,它并不适用于外部调用的Function(函数)。

4.Ctrl+Shift+Space快捷键

位置:依次选择QTP 上方菜单栏→Edit→Advanced→Argument Info。

在方法后往往需要设置一些参数,但是那么多参数难道都去背下来吗?显然不用,QTP 会自动提示该方法的参数,如图1-155所示。

但是有时候会因为某些操作导致参数提示消失了,此时就可以使用Ctrl+Shift+Space快捷键来重新显示参数提示,这个小功能相当实用。

5.基于类和函数的Complete Word

在上一小节中,介绍了QTP可以使用Ctrl+Space快捷键来激活Complete Word的功能,增强脚本的编写效率,此方法只能对于一些vbs函数进行智能提示,对于类是不支持的。那么在这里,作者介绍QTP的一个支持类的Complete Word。方法很简单:Alt+.(Alt键加“点”键的组合)。

首先,打开QTP,输入以下代码:

Class libClass

Function libFunction

Msgbox "libfunction"

End function

End Class

然后,使用Alt+.快捷键进行激活,如图1-156所示。

图1-155
图1-156

此方法只适用于QTP 9.2及其之前的版本。

6.学会使用With…End With

首先来一起看以下这段脚本:

'51Testing首页

Browser("51Testing软件测试网").Page("51Testing软件测试网")._

WebButton("WebButton").Click

Browser("51Testing软件测试网").Page("51Testing软件测试网")._

WebEdit("password").Set "Yu Jie"

Browser("51Testing软件测试网").Page("51Testing软件测试网")._

WebEdit("username").Set "Jerome Yu"

'百度首页

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Set "QTP自动化测试技术领航"

在上面这段脚本中使用了很多代码换行符,这个在前面已经介绍过了。不知道读者看了上面这段脚本以后有没有发现一个问题,那就是每句代码中前面半段都是相同的,比如现在要操作51Testing首页中的一些对象,不难发现不同操作对象前的祖父对象和父对象都是一致的,遇到这种情况,就完全可以使用With来解决,见下面这个脚本:

'51Testing首页

With Browser("51Testing软件测试网").Page("51Testing软件测试网") '注意后面没有点

.WebButton("WebButton").Click '请注意“点”的位置,句首需要有一个“点”

.WebEdit("password").Set "Yu Jie"

.WebEdit("username").Set "Jerome Yu"

End With

With就是用来提炼公共部分的,现在再去看脚本,是否一下子感觉清晰、有序了很多?又比如同一个脚本中需要操作两个网站,此时用With效果也非常好,见下面这个脚本:

'51Testing首页

With Browser("51Testing软件测试网").Page("51Testing软件测试网")

.WebButton("WebButton").Click

.WebEdit("password").Set "Yu Jie"

.WebEdit("username").Set "Jerome Yu"

End With

'百度首页

With Browser("百度一下,你就知道").Page("百度一下,你就知道")

.WebButton("百度一下").Click

.WebEdit("wd").Set "QTP自动化测试技术领航"

End With

如此一来,就可以很直观地读代码了,一目了然。With可以大大提高代码可读性,这同时意味着方便了我们以后的维护工作。

另外,可以随意“With”公共部分,也可以嵌套With,见如下脚本:

'百度首页嵌套在51Testing首页中

With Browser("51Testing软件测试网").Page("51Testing软件测试网")

.WebButton("WebButton").Click

.WebEdit("password").Set "Yu Jie"

.WebEdit("username").Set "Jerome Yu"

With Browser("百度一下,你就知道").Page("百度一下,你就知道")

.WebButton("百度一下").Click

.WebEdit("wd").Set "QTP自动化测试技术领航"

End With

End With

'百度首页 -- 提炼其他公共部分

With Browser("百度一下,你就知道")

.Page("百度一下,你就知道").WebButton("百度一下").Click

.Page("百度一下,你就知道").WebEdit("wd").Set "QTP自动化测试技术领航"

End With

因为好用,所以With…End With 是日常编程过程中经常使用的工具。

总结:

虽然本小节介绍的都是一些很小的应用技巧,但是往往能够给我们带来工作效率,QTP中的技巧也远远不止这些,相信更多的实用性技巧在于读者平时的挖掘与积累,作者认为,适合自己的才是最好的!

 

1.6.3 封装对象模型——Test Objects VS Run-time Objects

1.6.3.1 解密测试对象与运行时对象

在QTP 里的封装对象共分两个概念,一个是Test Objects(俗称TO)“测试对象”,另一个是 Runtime Objects(俗称 RO)“运行时对象”。可能大部分读者已经不记得了,在上篇介绍Spy的那个章节中,作者在末尾处已经初步提到过TO与RO,我们来回忆一遍吧,以下是原文:“最后作者要说下,也算是一个预告吧,后者也就是Identification Properties 以后会牵涉到对象库编程中的两个重大概念Test Objects(测试对象,俗称TO)和Run-time Objects (运行时对象,俗称RO),在为TO或RO进行编程的时候使用的就是QTP自己封装的这些对象属性。关于前者Native Properties 也有其独特的调用方法。”

原文中提到了Spy中的Native Properties以及Identification Properties,后者就是要在本小节重点讲的封装对象的属性,而前者会在后面介绍对象自身接口的属性时介绍。不过无论是哪一个,都和对象库编程有着紧密的联系,基于对象库的编程就是基于这些属性来完成的。

继续回到主题,TO和RO这两个概念从字面上来看并不是很好理解,也容易混淆。作者现在就用最简单的描述来介绍测试对象(TO)与运行时对象(RO)的区别:TO就是被添加到对象库中的对象,RO 其实就是被测试软件在运行时实际所运行的那个对象。但是,读者要记住,无论是TO还是RO,它们都属于QTP封装的对象,共同使用QTP封装好的一些属性,RO就有点特殊了,它也可以调用自身接口的属性,这个是在下个小节中要讲述的内容,读者在这里只要知道RO也调用QTP封装好的属性就可以了。

在上篇中已经讲解过QTP鉴别对象模型的机制Object Identification,QTP识别对象通常就是先在对象库里添加测试对象,这些对象全部都存有一些特征属性的值,然后在被测软件运行的时候,QTP会根据脚本里的对象名字,在对象库里找到相对应的测试对象,并根据这些对象的特征属性描述,在被测试软件里搜索并找到相匹配的实际正在运行的对象,最后就可以对这些实际运行的测试对象进行操作了。如果在这个过程中没有找到任何相匹配的对象,那么QTP就会报个“找不到该对象”的错误。最后,作者用最简单的一句话总结一下测试对象(TO)与运行时对象(RO)两者之间的紧密关系:测试对象是为了识别运行时对象而存在的。

1.6.3.2 三兄弟GETRO、GETTO、SETTO各显神通

在理解了Test Objects与Run-time Objects以后,就要开始学习如何获取到对象的属性了,毕竟自动化测试分成两大块,第一个就是自动操控被测对象。第二个就是获取各种所需要的对象属性,获取属性的作用也可以分成两部分,一个最重要的作用也是最常用的就是验证,验证离不开这些属性,只有这些属性才能证明软件的操作是正确的还是错误的,另一个用途就是获取到一些有利用价值的属性来做后续的事情。还有一个分支,就是给对象库里的对象通过代码自动设置一些属性,以达到特殊的测试目的和要求。所以,在自动化测试过程中,对于“属性”的掌控是很重要的,接下来就详细介绍操控属性的各种方法,待掌握以后再举一些项目中基本的实际使用例子来帮助读者理解各种方法的作用,并证明其实属性的获取是自动化测试过程的桥梁。所以,这些对属性操作的方法绝对是重点中的重点内容。那么就让我们看看对象属性的处理方法有哪些,并逐一进行介绍。

素材:www.baidu.com百度首页,所需添加对象如图1-157所示。

图1-157

1.GetTOProperty()

基本含义:获取对象库中某个对象的某个属性的值。

公式:ReturnValue =对象.GetTOProperty("封装属性名")

基础示例:

ValueOfTo=Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("新闻").GetTOProperty("text")

MsgBox ValueOfTo

运行结果与分析。

获得Link对象在对象库中记录的属性“text”的值,并返回给变量ValueOfTo,最后以对话框形式显示这个值,显示后的结果如图1-158所示。

图1-158

从图 1-158 中可以看到,已经成功获取到了该对象的“text”属性值并弹出对话框显示。在这里,读者需要注意,如果在实际运行的过程中,“text”属性已经发生了改变,假设变成了“贴吧”,在这里仍然是获取到“新闻”这个值,因为GetToProperty这个方法就是获取对象库中的对象的属性值。

企业项目案例臆测。

如果项目中碰到这样一个需求:界面上有一个test1的下拉框控件,每次在刷新页面后都会选中默认值A,现在业务中需要选择其他值,我们需要用QTP做比较。像碰到这种案例时,就可以通过使用GetToProperty和GetRoProperty(后面会讲到)这两个方法协助完成,只要在下拉框选中默认值的时候将其加入对象库,这样对象库中的记录值就永远会是这个默认值了,然后在实际运行时选取其他值,并获取此时这个对象的实际选取的值,最后对两个值做一个比较,通过这个思路就能解决这个需求了。

2.GetTOProperties()

基本含义:获取对象库中某个对象的所有属性的值。

公式:ReturnValue =对象.GetTOProperties()。

基础示例:

SetTestObject =Browser("百度一下,你就知道").Page("百度一下,你就知道").Image("百度首页logo") '1

Set Properties = TestObject.GetTOProperties() '2

PropertiesCount = Properties.Count '3

Print "对象总计存在" & PropertiesCount & "个封装属性。" '4

For i = 0 To PropertiesCount – 1 '5

PropName = Properties(i).Name

PropValue = Properties(i).Value

Print PropName & " = " & PropValue

Next

Set Properties = Nothing '6

Set TestObject = Nothing '7

运行结果与分析。

首先,GetTOProperties这个方法获取的是一个数组,这个务必要清楚。因为是数组,所以想要一个个打印属性值的前提条件就是,先要得到对象的属性个数,然后再通过循环的方法把一个个属性和属性值打印出来。但是,GetTOProperties并没有提供Count方法,所以,只能通过其他方式去获得对象属性的Count(见代码片中的1~3)。在获取到Count以后,就能够一个个将值读出来了(见3~5),当然,最后也别忘了释放对象(见6~7)。

为了更好地显示结果,所以才在这里使用了 Print 函数(QTP自带的函数,调用后会将一些信息填写到Print Log窗口中),最后就让我们一起来看一下打印结果,如图1-159所示。

图1-159

企业项目案例臆测。

一般情况下,在项目中很少会使用到 GetTOProperties 这个方法,因为通常不会碰到需要使用到这个方法的需求。所以, GetTOProperties 这个方法也是所有操作对象属性中最少使用的一个方法,也正是因为如此,作者才没将本小节的标题写成“四兄弟”。

3.SetTOProperty()

基本含义:设置对象库中某个对象的某个属性的值。

公式:对象.SetTOProperty“封装属性名”,“封装属性值”。

基础示例:

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").SetTOProperty"name","百度一百万下"

MsgBox "时间停止,大家一起欣赏此时对象库中WebButton"百度一下"的name值!"

运行结果与分析。

SetTOProperty方法的作用就是改变对象库中的值,当然,使用代码形式的修改对象属性属于临时性的,只在脚本运行时有效,一旦脚本运行结束,对象库里的属性值就会还原,它的生命周期是短的,不过已经足够我们做很多事了。

在本段代码片中,要修改的是WebButton(“百度一下”)这个控件在对象库中的属性,为了证明修改最终是成功的,那么让我们一起先来看一下修改以前的name属性值,如图1-160所示。

图1-160

从图1-160中可以看到,name的属性值是“百度一下”,然后作者把它改成了“百度一百万下”,我们前面讲过,由于SetTOProperty这个方法的生命周期很短,所以,如果要看到修改的效果,必须在脚本结束前,将脚本停住,所以,作者在脚本里加了一个MsgBox方法,并将本行设置断点,这样QTP就会停止下来,此时去刷新一下对象库就能看到百度一下这个按钮的name值已经改变了,如图1-161所示。

图1-161

如图1-161所示,此时对象库中“百度一下”这个控件的name属性值已经变成了作者所设置的“百度一百万下”,到此也证明了实验已成功。需要注意的是,使用SetTOProperty方法,后面的参数是不需要加括号的,因为它没有返回值,当然这是VB中的知识点,在这里稍许提一下,如果在这种情况下加括号是一定会报错的,切记!

小提示

在QTP中,断点的快捷键是F9,使当前断点不生效/生效的快捷键是Ctrl+F9,取消所有断点的快捷键是Ctrl+Shift+F9。

企业项目案例臆测。

可以和 GetToProperty 那个案例结合,假设现在需要将对象库中的对象属性值转变成其他指定的值,这种情况下,就可以使用SetTOProperty方法了。另外,使用SetTOProperty这个方法还有其他好处,比如可以解决一些共享对象库的对象修改和管理问题等。

这里还有一个很经典的自动化测试案例告诉读者,假设某个窗口上有很多待检查的记录,每条记录右边都有一个Check按钮用来检查各条记录。但是,记录个数是不定的,所以Check按钮个数也就不定,只有一个Edit控件显示记录个数。要对每条记录进行检查,也就是要点击每个Check按钮。但是Check按钮由于个数不定,根本没法将每个Check对象都添加到对象库中,因为个数可能太多了(上百个),如果硬要一个个添加到对象库中,是很烦的事。在这里告诉大家一个好办法,就添加一个 Check 按钮对象,它设有两个特征属性,分别是:label=OK、index=0,然后用下面的脚本就可以完成该自动化任务了:

buttonNum = CInt(JavaWindow("Test").JavaEdit("Record Num").GetROProperty("value"))

For buttonIndex = 0 to buttonNum -1

JavaWindow("Text").JavaButton("Check").SetTOProperty("index",buttonIndex)

JavaWindow("Text").JavaButton("Check").Click

Next

分析:这段脚本的第一行代码是先通过Edit控件来获取页面上Check按钮的个数,然后通过循环并利用 SetTOProperty 方法一个个地去改变对象库中那个添加好的 Check 按钮对象的index,这样只需要添加一个对象就可以实现N个相同对象的操作了。

或者还有这样一个经典案例,假设窗口上有New、Modify、Delete、Check 等好几个按钮对象,需要把这几个按钮一一按过去,这种情况下也只需要在对象库里只添加一个按钮对象就可以了,假设它叫“AnyButton”,label的特征属性值随意填写即可,然后用下面的脚本来实现:

JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label","New")

JavaWindow("Test").JavaButton("AnyButton").Click

JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label","Modify")

JavaWindow("Test").JavaButton("AnyButton").Click

JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label","Delete")

JavaWindow("Test").JavaButton("AnyButton").Click

JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label","Check")

JavaWindow("Test").JavaButton("AnyButton").Click

4.GetROProperty()

基本含义:获取实际在运行时的某个对象的某个属性的值(不是从对象库里面获取)。

公式:ReturnValue =对象.GetROProperty("封装属性名")。

基础示例:

ValueOfRo = Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("搜索内容编辑框").GetROProperty("value")

MsgBox ValueOfRo

运行结果与分析。

首先,GetROProperty 方法访问的是实际正在运行的对象的封装接口,在这里做一个实验来证明这个方法的效果。第一步就是添加WebEdit这个“搜索内容编辑框”控件到对象库中(注意,在还没有输入过任何字符的时候进行添加),添加完以后可以看到对象库中该对象的value属性的值是空的,如图1-162所示。

图1-162

如图1-162所示,value的值是空值,因为还没有在编辑框中输入任何值的时候添加的。接着做第二步,在编辑框中输入“QTP自动化测试技术领航”,如图1-163所示。

在完成这些操作后,执行下代码片中所写的脚本,其结果显示如图1-164所示。

图1-163
图1-164

图 1-164 中显示的结果已经很明显了,证明了 GetROProperty 的方法是获取实际在运行时对象的属性值“QTP自动化测试技术领航”,而不是该对象在对象库中的值“空值”。细心的读者一定会发现,刚才在查看对象库中 WebEdit 控件 value 值的时候,是通过点击 Add Properties按钮,然后在弹出的界面中看到的,作者在这里只是看了一下这个属性的值,并没有将这个属性添加到Description Properties 窗口中,知道为什么不能添加到该窗口吗?因为一旦添加进去,QTP 就会报错了。在之前的内容中讲过 QTP 识别对象的机制,就是通过Description Properties窗口去匹配的,如果把value属性加到这个窗口下,那么在输入“QTP自动化测试技术领航”这些字符以后,实际运行时QTP就会因为识别不了对象而导致报错,因为Description Properties窗口下所有的属性都是必须要匹配到的识别属性。

企业项目案例臆测。

GetROProperty方法在项目中使用率就太广泛了,几乎所有的验证点都需要使用这个方法。比如注册功能,在提交一些注册信息以后,一般都要到接下来的确认页面去验证一些信息,这些值都是动态的,在这里就能使用 GetROProperty 这个方法来动态获取实际运行时的一些确认信息,然后和所预期的测试数据做对比就可以了,这样就达到了自动化测试的目的。

总结:

属性对于自动化测试的重要性就不再老生常谈了,在刚接触QTP的时候,对于对象的封装属性都还不熟悉,此时Spy对我们来说就太重要了,用好Spy就可以轻松查到封装对象有哪些属性了,从而选择那些可利用的关键属性来完成自动化测试业务需求。除了 Spy,只要有其他工具能探测到对象属性,那也是一样的,比如可以自行开发一个探测工具。在这里,也推荐给读者一个Spy的黄金搭档(只针对Web系统),那就是微软的IEDevToolBar,它同样也是一个探测工具,它可以轻松探测到节点和节点的属性名及其值,有兴趣的话可以网上搜索一下或者到微软的官方网站下载。

另外,相信读者应该已经发现,在 QTP 中使用封装方法对测试对象进行操作,只提供了 SetTOProperty 这一个方法来对属性进行设置和修改,其他的方法都是在做一些获取属性的操作。但是,SetTOProperty 这个方法只能修改对象库中对象的值,那有没有修改实际运行时对象的属性的办法呢?答案将会在后面揭晓……

1.6.3.3 对象封装属性的真正源头

在介绍Spy的那个章节中,我们就已经介绍过Identification Properties下会显示很多对象的封装属性,如图1-165所示。

图1-165

如图1-165所示,WebEdit控件的封装属性数量还是相当可观的,不光图中显示的这些,还可以通过右侧拖动滚动条看到更多的属性。这些属性都是可以通过 GetROProperty方法进行访问的,这个在上一节中刚讲过,这里就略过了。在这里主要是介绍一个特殊的属性,它就是Class Name(见图1-165中第一个属性),这个属性在介绍Spy的那节中就已经介绍过。刚才说过了,凡是封装属性的值都可以通过GetROProperty方法去获得,那么,现在执行下面的这段代码,看看是否能够获得Class Name的值,预期结果应该是“WebEdit”(见图1-165):

msgbox Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").GetROProperty("ClassName")

待QTP执行完这段代码以后,我们一起来看执行后的结果,如图1-166所示。

为什么获得的值是个空值?应该是“WebEdit”。图 1-165 中都是这么显示的。其实是因为QTP 封装此属性的名称不是Class Name,而是micClass,不信?那我们执行下面这段代码再试试看,是不是会获取到“WebEdit”这个值:

msgbox Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").GetROProperty("micClass")

QTP开始执行,结果如图1-167所示。

图1-166
图1-167

如图1-167所示,结果已经看到了,就是想要的预期结果。此时,读者一定会问,为什么是miClass,而不是Class Name 呢?为什么作者就知道是micClass 呢?连Spy 里显示的都是Class Name 啊!别急,答案很快就会揭晓!

首先,我们运行regedit来打开注册表,然后进入到以下位置:

HKEY_CURRENT_USER -> software -> Mercury Interactive -> QuickTest Professional -> MicTest ->Attributes

当展开Attributes这个目录时,会看到很多熟悉的属性。没错!这里就是QTP所有封装属性的集结地,如图1-168所示。

图1-168

在这个目录下可以找到 micClass 属性(见图 1-169),而 Class Name 属性是没有的,所以刚才打印出来的值是一个空值就是这个原因。

图1-169

另外还有很多QTP隐藏的封装属性,并且这其中一部分属性在QTP的所有帮助文档中都没有提到过。在这里,作者就随便找一个 Spy 中没有的封装属性来试试,以 source_index为例,来看下面这个脚本:

'获取封装属性source_index的属性值

index = Browser("百度一下,你就知道")._

Page("百度一下,你就知道").WebEdit("wd").GetROProperty("source_index")

'在这里对WebEdit控件使用了描述性编程就是为了证明source_index是个隐藏属性,Spy中是没有的,关于描述性编程,读者先不用关心,后续章节中会详细介绍

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("source_index:=" & index).Set"QTP自动化测试技术领航"

执行上面这个脚本后,就可以看到百度搜索框成功输入了“QTP自动化测试技术领航”。它的原理主要是通过 source_index 获取对象的索引,并通过描述此属性成功对此对象进行控制。

通过这个实例,我们终于明白了对象封装属性的真正源头到底在哪里!在这个目录下不光可以看到一些平时所常用的一些隐藏属性,例如,creationtime、index等,还有很多从来没有看到过的隐藏属性,有兴趣的读者可以每个都去尝试一下。

注意

每个属性都是有对应的对象的,比如creationtime属性只能用在Browser对象上,这点需要读者认知的。

 

1.6.4 梳理运行时对象的封装与自身接口的属性区别

1.6.4.1 解读对象的自身接口

在上一节中,作者已经介绍过实际上运行时的对象是有两种接口的,第一个就是上一节中主要讲解的对象封装接口,另一个就是将在本小节中重点介绍的对象自身接口。首先让了解一下两种接口的区别。

封装接口是对象的不完全属性,有些对象的属性值是封装接口无法获取得到的。

运行时的对象(RO)可以看见自身接口的所有属性,而对象库中的测试对象(TO)只可以看见被封装的一些接口。

封装属性是不能修改实际运行时的对象的,只能获取属性的值,而调用自身接口就可以。

以上3条就是封装属性与自身接口属性两者间的区别,其实读者应该不难发现这两者之间有本质上的一个特性,那就是封装接口既支持(或者叫涵盖吧)对象库中的测试对象,同时也支持运行时的对象,而自身接口就只支持运行时的对象,这点千万要注意,也不要搞混了,对于初学者来说这是一个难点和容易混淆的地方。

1.6.4.2 教你如何成为一名黑客

虽然现在读者已经了解了对象分测试对象与运行时对象,运行时对象除了有封装接口之外还有一个自身接口,但是这些都是概念上的内容,相信读者还是不明白自身接口到底是什么。在这里作者卖个关子暂且不告诉大家,先来玩一个有趣的“魔术”,作者在这里扮演一个黑客的角色,将这本书的推广方“51Testing”给黑掉。在袭击51Testing官方论坛首页之前,还是先让广大读者再看一下,因为过一会它将会变得面目全非:

如图1-170 所示,目前51Testing 的论坛还是原样,一会,作者将“51Testing”网站给黑掉,如图1-171所示。

图1-170
图1-171

如图1-171所示,51Testing网站界面上的某些控件经过作者的“施法”已经被替换成了百度网站中的一些控件,一共发生了4处变化,已经在图1-171中标注,它们分别是。

(1)将WebButton控件“登录”改成“百度搜索”。

(2)将Image控件“51Testing的Logo”改成“百度的Logo”。

(3)将Link控件“加入51Testing(注册)”改成“加入百度(注册)”。

(4)将Link控件“登录”改成“baidu_login”。

读者现在一定是非常的兴奋(很正常,当初作者也是如此的兴奋),为什么作者的手段那么厉害,能如此轻易地攻击一个大型网站。首先,作者可以告诉广大新人,作者的“帮凶”不是别人,正是这个强大的自动化测试工具QTP。所以,作为新人的你是不是一下子对QTP产生了浓厚的兴趣?的确是这样的,一旦学会了如何去当一名“黑客”,你一定会对QTP兴趣倍增,而且一旦学会了黑客之道,也同时证明了你的QTP水平已经上了一个台阶。

接下来作者将这个“魔术”表演分享并分解给读者,首先作者展示实现这个“魔术”表演的QTP脚本代码如下:

With Browser("51Testing软件测试论坛").Page("51Testing软件测试论坛")

.WebButton("搜索").Object.value = "百度搜索"

.Image("51Testing_Logo").Object.src = "http://www.baidu.com/img/baidu_sylogo1.gif"

.Link("加入51Testing(注册)").Object.innerText = "加入百度(注册)"

.Link("登录").Object.innerText = "baidu_login"

End With

上面这个脚本就是完成这个“魔法”的“功臣”,现在就来揭晓为什么作者可以轻易地改变51Testing网站!其实,就是因为使用自身接口修改了正在运行时的对象,所以才出现了图 1-171中的假象。在上一小节中作者就已经介绍过了封装对象接口和自身接口的区别,其最后一条说的就是“调用自身接口就可以修改实际运行时的对象的属性值”。不过,它的确是假象,只需要刷新网页,51Testing网站就恢复原貌了。不过如果不刷新网页,那么这个“魔术”还是继续有效。比如作者假设把“注册”功能屏蔽掉,那的确是不可能点击到“注册”按钮的。这个实验作者也将留给读者去尝试,作为本章节的练习内容。

在了解这个魔术背后的秘密之后,一起来看一下调用自身接口的公式。

对象.object.自身属性,示例如下:

Browser("百度").Page("百度").WebButton("百度一下").Object.innerText = "百度一百万下"。

分析:以上代码是将WebButton("百度一下")这个对象的自身接口属性innerText设置成其他属性值“百度一百万下”。

对象.object.自身方法,示例如下:

Browser("百度").Page("百度").WebButton("百度一下").Object.click。

分析:以上代码调用 WebButton("百度一下")这个对象的自身接口的方法 click,以自身接口的方式完成点击操作。

另外,自身接口不但可以设置运行时属性的值,同样也可以获取运行时属性的自身接口的属性值,先来看图1-172所示。

现在,要通过调用自身接口的方式来获取动态运行时的“百度搜索框”的内容,示例代码如下:

getContent = Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Object.value : MsgBox getContent

分析:以上代码是获取 WebEdit("wd")这个对象的自身接口的属性“value”的属性值,然后弹出对话框显示出这个属性值,如图1-173所示。

图1-172
图1-173

小提示

注意到上段代码中MsgBox…和getContent…处于同一行代码了吗?难道没有疑问吗?这样QTP 为什么没有报错?其实答案就在于在代码中加了“:”冒号。冒号在这里的作用就是连接本不相干的两句或N句代码使其合成一句。如果不加冒号,那QTP一定会报错。

到此,相信读者一定会产生这样一个疑问,那就是如何知道获取content就是用value这个自身接口属性?其实这个完全是凭经验的,作者一开始也不知道,做过了就明白了。新人在平时可以多用Spy去了解对象的属性(自身接口的、封装的一个都不能落下)并逐一尝试,过不了多久就可以熟悉了。

既然获取的时候用 value 这个属性值,那么,如果要对搜索编辑框输入一个值该怎么操作呢?同样也是要用到 value 这个自身接口属性值。先让我们来回顾一下如何用封装接口进行赋值操作,代码如下所示:

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "Yu Jie"

紧接着,用自身接口的方式,代码如下所示:

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Object.value = "Jerome Yu"

最后,一起来见证是否调用自身接口也能为百度搜索框赋值,如图1-174所示。

图1-174

在结束这个知识点的介绍前,作者再次强调自身接口是无法调用对象库中的对象属性值的,读者务必记住!此外,作者还要分享给读者一些需要注意的地方,相同的属性名在自身接口和封装接口中的显示有所不同,以最常见的INNERTEXT来举例,如图1-175和图1-176所示。

图1-175
图1-176

如图1-175和图1-176所示,我们可以看到,在自身接口中显示的是“innerText”,T是大写的,在封装接口中则显示的是“innertext”,全是小写。举个例子,假设前者 innerText的值等于A,现在需要获取这个值,如果此时误写成innertext的话,获取的值将是一个空值,就完全与预期不一样了,所以,读者务必要注意到这点,一开始会很容易犯错,而这些小错误对于没经验的新人来说很难察觉到,因为代码并没有错,所以QTP也不会报错。

 

1.6.5 几种常见对象无法识别或识别错误的原因

对象库的整个学习过程即将结束了,无论是调用封装接口还是调用自身接口,它们都要有一个大前提,那就是对象能够被QTP识别。但是往往在自动化测试过程中,会碰到很多对象无法正确识别或识别错误的情况,作者进行了一下总结,以下几种原因是最常见的。

1.软件程序的对象控件无法被QTP识别

QTP毕竟不是万能的,很多软件的对象控件都无法识别到,尤其是C/S架构的软件程序,大多数控件都是 WinObject。碰到这种情况,在第一章节中就说过了,此类项目是不适合用QTP做自动化测试的,当然如果必须要做自动化测试,通常有以下几种解决方案。

(1)设置虚拟对象。

先来知悉虚拟对象的方位,如图1-177所示。

图1-177

如图1-177所示,该位置就是虚拟对象,存在两个功能,新增虚拟对象和管理虚拟对象。作者在这里不对此功能多做介绍,因为并不推荐这个方法,即使依赖虚拟对象解决了所有不能识别的对象,但以后的对象维护工作是根本没法继续下去的,而且虚拟对象本身就非常脆弱,即使对象没有发生变化,但是,只要对象在界面上的方位发生变化,虚拟对象就会识别失败。所以,读者只需要了解一下这个功能就可以了,感兴趣的读者不妨尝试着亲自设置一些虚拟对象。

(2)使用相对坐标然后配合WSH去定位对象。

当碰到对象无法识别的时候,还可以通过这种办法尝试解决。因为即使是一个 WinObject对象,它仍然有坐标,所以,使用相对坐标则可以帮助动态定位对象的位置,然后再使用WSH去对这个WinObject做一些操作(当然,这些操作不可能非常全面)。还比如,虽然对象无法识别,但是它支持快捷键操作,比如使用“Ctrl+O”的快捷键组合可以打开某个东西,遇到此类情况,也可以使用 WSH 来巧妙地完成想要完成的业务(虽然对象仍然是不能识别的,但是只要能达到预期目标,任何方法都是好方法)。关于WSH的知识点会在后续的章节中详细介绍。在本小节中,读者只需要知道常见的对象无法识别案例和相应的解决方案即可。

(3)使用DOM组件接口应用技术。

DOM 的全称是Document Object Model。这种办法只可用于Web 项目。举个例子,淘宝网的密码输入框用正常的Set方法是无法操作的,此时就可以调用DOM的GetElementById方法,然后进行密码输入的操作。DOM也会在后面的章节中详细介绍,这里不多做阐述。

(4)使用QTP 自定义扩展SDK Customer来进行二次开发使QTP 能够识别对象。

这个属于QTP中最高深的技术。目前关于此方面的技术文章在QTP学习网站中都是非常少的。本书的作者曾录制过两个教学视频介绍此方面内容,如果读者有兴趣可以联系本书的两位作者,在本书的末尾有作者的联系方式。

(5)开发提供专属插件。

作者曾经有过类似的自动化测试项目经历,对象基本都无法识别,但是自动化测试需要做下去。于是开发了专职对象识别脚本,然后利用 QTP 这个平台去执行自动化测试。像这种情况,其实自动化测试的主力就已经不再是QTP了。

(6)把无法识别的对象的一些方法封装到一个dll中并使用QTP调用。

这个方法和上面的有所区别,自动化测试主力仍然是QTP,在QTP中有一个Extern对象,这个对象就是专门司职外部dll调用工作的,开发只需要把各种方法封装成一个dll即可,关于调用外部dll的技巧同样会在后面的章节中介绍到。

2.对象可以被QTP识别,但是加载的插件不正确

发生这种情况总体来说还是幸运的,因为毕竟这也许只是一个误操作,只需要重新加载相对应的正确插件,QTP就可以为你服务了。

3.同一个界面中存在两个或两个以上的属性相同的对象

有这么一种情况,同一个页面中存在多个属性相同的对象,这种时候QTP会报错并在报错信息中提示我们。像遇到这种问题时,最直接的解决办法就是为每一个对象做一个唯一标识符,最常见的就是设置Index。

4.实际运行时的对象发生了改变导致与对象库不匹配

在自动化测试过程中,很多对象都是动态的,在运行时,属性是一直在发生变化的,比如句柄。碰到类似的问题,解决思路就是先动态获取运行时的值,然后将这个值动态添加到对象库对象中,这样就可以轻松解决该问题了。如何动态获取运行时的值,如何将值动态添加到对象库对象中,这些都是前面的重点内容,读者如果有所遗忘,请重新回顾!

 

1.6.6 总结

本章节和上一个章节不同,主要是围绕如何去实现脚本。这两个章节合起来几乎涵盖了对象库编程所有的精华部分,读者务必要学精、学透。作者已经给了方法,接下来就是要通过大量的实践和反复的练习真正地驾驭好它。

对象库编程的确是相当好用的,QTP高效编程的3种方式也都是基于对象库的,这些高效的方法是不基于在下面的章节会介绍的描述性编程的。所以,一般情况下,作者建议使用对象库编程。

 

知识点巩固和举一反三练习

一、过把“魔术师”或黑客的瘾!

要求1:根据图1-178和图1-179中的数字标识依次按要求慢慢“吞噬”百度首页。

图1-178
图1-179

(1)将Title和Tab变成“QTP自动化测试技术领航”。

(2)将Logo变成51Testing首页的Logo,URL为www.51testing.com。

Logo图片来源:进入51Testing首页后,右键单击网站Logo后,在弹出的菜单中点击属性,复制URL,如图1-180所示。

图1-180

(3)将贴吧变成“51Testing专家博客”。

(4)将搜索框禁用(无法输入任何文字)。

(5)将[百度一下]按钮变成“51搜索”。

(6)将“把百度设为主页”变成“把51Testing设为主页”。

(7)将“加入百度推广”变成“加入51Testing推广”。

(8)将“关于百度”变成“关于51Testing”。

(9)将“About Baidu”变成“About 51Tesing”。

(10)将该处文字替换成“©201151Testing测试自动化系列丛书-QTP自动化测试技术领航”。

要求2:提取公共部分代码,提高代码维护性、直观性。

二、分别使用已学过的QTP编程的3种方式来完成第一题。

要求1:熟练运用并掌握,然后评价出你觉得最适合你的一种方式。

 

1.7 描述性编程(Descriptive Programming)

阶段要点

• 描述性编程不高深。

• 描述性编程的两种写法。

• 描述性编程实例介绍。

 

1.7.1 一点都不高深的描述性编程技术

QTP刚进入国内不久时,各大测试论坛曾经有过一场持续了多年的争论,引起这场争论的导火线就是对象库编程(以下简称ORP)和描述性编程(DP)。这场争论持续了至少3年以上。争论的话题都是使用QTP进行自动化测试,其测试脚本是使用对象库编程好还是描述性编程好,有兴趣的读者完全可以在51Testing论坛中输入一些关键字进行搜索,如“对象库描述性编程”等,相信应该还能重新找到不少信息。

大约从2009年开始,随着大家对QTP技术的了解,ORP与DP的争论已经越来越少了,因为随着时间的推移,国内的QTP自动化测试技术也发展到了一定高度,使得越来越多的测试人员更倾向于ORP!为什么?ORP技术为什么好过DP技术?有什么依据?暂时先不说,先说说大多数当初支持DP的人们的一些心态:

第一种也是最典型的一种,就是描述性编程这个名词里嵌套了“编程”两字,这得怪Mercury开发QTP的时候提出了DP这一概念!这“编程”两个字可误导了不少测试新人。相信大家都知道,国内测试行业的很多新人大多都是其他行业转型过来的,相对做测试的门槛没有做开发那么高,很多也没有经受过系统的计算机软件方面的学习,所以对“编程”一直很向往,觉得编程很难,所以一听到QTP的描述性编程这个概念,就觉得是个很高深的技术。在早期,就是因为这种心态使得一大批测试新人在慢慢熟悉并会使用QTP以后,明明可以不去使用 DP 也硬要去使用,以显示自己是技术牛人,其实这种举动是化简为繁并脱离了自动化测试的本意。当然,很多支持 DP 的人不是属于炫耀范畴的,是属于被“编程”两字忽悠了的范畴的。

第二种也是比较典型的,因为以前大家都认为DP很高深,觉得DP是QTP中的精髓。所以,如果使用 DP 写脚本并提交给测试经理看,那领导一定会认为你很牛。很明显,以上两种都是稍许带有贬义的。

第三种争论的焦点是自动化测试框架,配合自动化测试框架,在进行QTP编程的时候到底用ORP好还是DP好?这个也可以说是3个中唯一一个真正对国内自动化测试领域的提高有价值的争论,因为的确是各有好处的!关键不是使用哪种QTP编程技术,更多的焦点是框架设计的怎么样。

所以,排除第三种自动化测试框架的特殊情况,选择ORP技术的人们是理智的人群,咱也不能说选择DP的人们就是不理智的,但是可以肯定,如果明明可以使用ORP技术却还硬要使用DP技术的人们是肯定不理智的。

很自然的,对象库编程就是我们上一章节刚刚重点介绍过的非常强大的一个功能,而描述性编程就是本章节要介绍给各位新人读者的一项编程技术。其实呢,本人一开始听到QTP的描述性编程技术的时候也一直以为是一门很高深的技术。事实上……下面就会用实例证明给大家看,其实DP就是这么简单的一回事!现在基本上大家都认可了ORP是QTP自动化测试的首选,为什么?因为ORP的确经得住考验,而且在下面的“终极对决”的小节里,还会让ORP和DP来一次大“PK”来证明,为什么选择ORP是理智的,为什么大家最终还是倾向于ORP,并且还会介绍一下ORP相比DP的一些优越性。

 

1.7.2 掌握描述性编程的两种写法

首先,需要用最简单和生动的例子来介绍描述性编程的概念,或者说它到底具体是什么,我们仍然用百度页面,请先看下面图1-181以及代码段。

相信读者应该都已经很熟悉图1-181了,它是一个对象库,里面添加了一些需要操作的百度网站的对象。接下来我们来看代码的实现:

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Set "QTP自动化测试技术领航"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

以上这段代码读者应该也已经很熟悉了。它就是用对象库编程产生的代码。但是,读者有没有思考过一个问题,假设这些对象没有添加到对象库里怎么办?QTP还能工作吗?完全可以!QTP 提供了描述性编程(Descriptive Programming)这个解决方案。事实上,在很多情况下,对象都不会顺我们的意思,经常会面临“不是我们想不想把对象添加到对象库,而是根本没法添加”这种尴尬局面。所以,此时“DP”可以担起重任了,替“ORP”完成它无法完成的事!这里暂时先不介绍无法添加对象的案例,我们先存心使对象无法生存于对象库中。把之前添加好的百度的对象全部删除,如图1-182所示。

就像我们现在看到的一样,已经没有对象供我们使用了,怎么办?当前需要做的唯一的一件事是“照搬”!搬什么?虽然对象库里的对象没了,但是我们完全可以将对象库中的内容直接搬迁到脚本中去。又是什么内容是需要搬迁到Expert View 中去的呢?——就是我们所要用的对象的一个个属性及其属性值,一起来看下是怎么搬迁的,推序如下所示:

图1-181
图1-182

'代码1

Browser("micClass:=Browser").Page("micClass:=Page")._

WebEdit("name:=wd").Set "QTP自动化测试技术领航"

'代码2

Browser("micClass:=Browser").Page("micClass:=Page")._

WebButton("name:=百度一下").Click

描述性编程大解析(第一种)。

整个搬迁过程完成了,这就是描述性编程,最简单地说,DP 无非就是在描述每个对象的属性和属性值,通过这个原理来虚拟成对象库中的对象,只是对象库是隐形的。

那先来看看第一句代码(代码 1):描述性编程的运作原理完全是和对象库编程一致的,所以在这里先去描述一个最“上层”的对象“Browser”,对象名称写好以后用上一对括号,然后在括号里依次从左到右填入引号、一个属性名称、一个冒号、一个等号、一个属性值、引号。这个就是第一个形式,即:对象名("属性名:=属性值")。读者必须要记住这个形式(描述性编程的形式一共有两种,在后文中会继续介绍第二种),有了前面的描述模板,接下来就完全可以依葫芦画瓢了。按照对象的结构顺序一层一层地往下描述,直到定位到最终想要操作的对象,最后给它一个方法,整个过程就结束了。看脚本中的代码1就是这样的。所以,同样的道理在代码2中就不讲了。

再总结一下,其实描述性编程就是将原对象库编程中括号内的“对象名”(见图1-183)换成一种描述语言,它描述的仍然是这个对象,只不过不再是封装好的现成的对象,而是需要现场描述(封装)。

图1-183

第一种描述形式已经介绍完了,但是关于第一种描述性编程方式的内容还没有讲完,在前面那段代码中,都是以单属性及其属性值来描述一个对象。其实在QTP中,还可以同时描述多个对象,但是数量还是会有一个极限的,可以描述的属性必须是QTP内置的(怎么才能知道哪些属性是QTP内置的,可供我们描述的,以及一些属性值的设置等,都会在下一小节的内容中介绍到),先让我们一起来看下面这段脚本:

'代码1

Browser("micClass:=Browser").Page("micClass:=Page")._

WebEdit("html tag:= INPUT","name:=wd").Set "QTP自动化测试技术领航"

'代码2

Browser("micClass:=Browser").Page("micClass:=Page")._

WebButton("html tag:= INPUT","name:=百度一下","type:= submit").Click

上面这段代码中,同样也是两句代码,第一句的最终定位对象用了两个属性去描述,第二句的最终定位对象则用了3个属性去描述。在这里同样要告诉读者们必须记下来的一个规则,那就是描述多个属性时,属性间用逗号隔开,这个逗号必须是英文状态下的。另外,描述性编程的语法是对了,但是如果描述的属性值没有设置对,那QTP是不会执行的,例如,假设将上面这段代码中的第二句代码中的最终对象“WebButton”所描述的属性 type 改成“error”这个值,其结果读者可以自行去尝试下,看看QTP会不会执行。

还要让读者记住第二条规则,那就是如果父对象描述了,子对象则一定要描述,不然QTP会报错,来看下面这个示例脚本:

'正确 – 父对象如果描述了,子对象必须描述

Browser("micClass:=Browser").Page("micClass:=Page")._

WebEdit("name:=wd").Set "QTP自动化测试技术领航"

'错误 – 父对象描述了,子对象没有描述

Browser("micClass:=Browser").Page("百度一下,你就知道")._

WebButton("百度一下").Click

图1-184是父对象描述后子对象没有描述导致QTP报错的截图。

图1-184

但是子对象如果描述了,父对象可以不描述,当然,父对象不描述又不报错的前提是要被添加到对象库中,一起来看下面这个示例脚本:

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("name:=wd").Set "QTP自动化测试技术领航"

至此,第一种描述性编程方式的基本内容全部介绍完毕。

描述性编程大解析(第二种)。

现在要介绍第二种描述性编程方式,那就是使用Description对象。使用该对象可以返回包含一组Property对象的Properties集合对象。Property对象由属性名和值组成。然后,可以在语句中指定用返回的Properties集合代替对象名(每个Property对象都包含一个属性名和值)。

要创建Properties集合,需要先创建Properties对象,使用以下语法进行:

Set ObjDescription = Description.Create()。

创建完毕后,就可以在运行会话期间在 Properties 对象中添加、编辑、删除或检索属性和属性值了。也可以这么理解,就是将对象的属性及其属性值的描述封装在一个特殊的Description对象中。例如,假设现在需要完成以下这个操作,见下面这个脚本:

Browser("micClass:=Browser").Page("micClass:=Page")._

WebEdit("html tag:= INPUT","name:=wd").Set "QTP自动化测试技术领航"

完全可以通过Description对象来实现同样的功能,参见下面这段代码:

Set ObjBrowser = Description.Create()

ObjBrowser("micClass").Value = "Browser"

Set ObjPage = Description.Create()

ObjPage("micClass").Value = "Page"

Set ObjWebEdit = Description.Create()

ObjWebEdit("html tag").Value = "INPUT"

ObjWebEdit("name").Value = "wd"

Browser( ObjBrowser ).Page( ObjPage ).WebEdit( ObjWebEdit )._

Set "注意此时描述对象的括号内是不需要加引号的,加了引号反而就错了!"

'最后需要记住释放对象,可以从最里面一层开始释放直到最外面一层

Set ObjWebEdit = Nothing

Set ObjPage = Nothing

Set ObjBrowser = Nothing

两种描述性编程方式都已经介绍完了,本人认为第一种更适合应用于普通脚本中,或者这么说,在对象库编程无法完全任务的时候,描述性编程临时加上一句,这样做显得更加直观,代码数量也更加少。但是很明显的缺陷就是无法做到复用。第二种描述性编程的方式,个人认为更适合应用于基于框架的脚本中,从表象上看虽然比前者会多写几句代码,但是这种方式的复用性远远优于前者,所以,具体选取哪一种方式都应按项目的实际情况界定。

 

1.7.3 Object Identification与Spy结合DP的妙用

在前面的章节中,已经认识了 Object Identification 和 Spy,在本小节中,这两位老朋友又要粉墨登场了。它们不止可以与对象库编程结合,同样可以和描述性编程结合。接下来,就分别聊聊它们与描述性编程的默契搭配。

在前面的小节中已经将描述性编程的语法教给大家了,语法是固定的就两种,但是描述的属性就非常多了,相信很多读者都已经开始疑问或者迷茫了,怎么知道哪些属性可以描述,全背出来了?其实不可能啦!本书在一开始的章节中就提到学习QTP是任何知识点都不用背的。所以,在这里本人公布:首先介绍的是Object Identification。通过O\I就可以知悉一切对象可描述属性,如图1-185所示。

图1-185

如图1-185所示,这就是O\I的界面,应该很熟悉了吧,之前都已经认识了,所以在这里一些基本介绍就不重复了。现在选中的就是刚才描述过的一个控件“WebButton”,默认出现在 Mandatory Properties窗口里的就是系统默认的一些该控件的重要属性,如果要描述一个控件,首先先描述这些最重要的属性(也许这种说法不科学,但是本人觉得这说法很实际和现实)。如果默认的属性满足不了你的需要,那你只需点击Add/Remove就可以了,里面可以让你新增或删除一些其他的属性,如图1-186所示。

图1-186

当然,不但可以删除一些备选的属性,也可删除系统默认属性。另外,在此主要要讲一下Browser和Page对象的描述,先来看看O\I吧,如图1-187和图1-188所示。

图1-187
图1-188

我们可以看到,Browser和Page是没有系统默认属性的。因为这两个控件比较特殊,一般情况下,都会使用Class Name 或者creationtime 这两个属性来描述该对象,它们在O\I 里可是没有的。Class Name可以从Spy里看到,说到Class Name我们也不得不回顾一下之前讲过的一个挺重要的知识点,就是Class Name必须要写成micClass。读者再返回看看在上一个小节中,描述Browser和Page的时候是不是使用了micClass?

接下来讲解的是Spy,Spy在描述性编程中也是经常被调用的,因为O\I用于定位所要描述对象的属性,而Spy就是定位描述属性的属性值,它们绝对是默契的搭档!描述性编程也就是因为有了它们,才可以应用起来,如来看看下面这张Spy图,如图1-189所示。

图1-189

本小节的内容相对比较简单,不过简单不代表实用性就不高,恰好是相反的!最后,告诉读者描述性编程可描述的属性都是封装接口属性,不是自身接口的属性,务必切记!

 

1.7.4 描述性编程的妙用以及与对象库编程的混搭

本人是不支持使用纯描述性编程的,DP 的使用应审时度势且以实用的角度出发。前面也讲到过了,一般情况下,描述性编程应用在对象库编程无法完全满足需求的时候,以替补的身份去出色完成少额的任务。但是要遵循一个原则,那就是不到必不得已(对象库编程实在没法解决),绝对不要去使用描述性编程,千万要杜绝想使用了就随意使用的情况。这样做有什么好处?最大的好处就是可以使脚本一目了然从而增加了可维护性!当一段脚本中都是对象库编程,突然有一行出现了描述性编程,那即使过了几个月后再看脚本,我们也可以马上明白,当前步骤是比较特殊的,是对象库编程完成不了的。反之,如果不养成这个好习惯的话,那整个脚本的层次就会显得非常乱,时间久了一定分不清哪些使用描述性编程的语句属于没必要范畴,而哪些属于必要范畴。

接下来,就举一些项目中需要使用到描述性编程的案例。

(1)百度首页有很多相同的Link控件,如“新闻”、“网页”、“图片”等,全部添加到对象库很麻烦,那么该如何使用描述性编程完成?

首先,先来看下场景图,如图1-190所示。

图1-190

一个首页就有接近 20 个相同类别的控件(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:=MP3").Exist

Print .Link("name:=图片").Exist

Print .Link("name:=把百度设为主页").Exist

Print .Link("name:=搜索风云榜").Exist

Print .Link("name:=About Baidu").Exist

End With

Set baidu = Nothing

执行脚本以后的结果就是在Log窗口内写8行True,返回True就说明描述的对象存在了,也就说明描述性编程成功了,如图1-191所示。

图1-191

分析。

这段脚本首先用 Set 将公共部分进行了提炼,这样可以使重复的部分合为一个整体。然后完全还可以进行优化,所以,选择使用With将所有会被复用的代码提炼出来(这里指Baidu),这样整个脚本就显得非常清晰了。

这也是描述性编程常用情况之一的最基本的一个情况:同一个界面中出现很多个相同类别的控件元素。

(2)如果要同时操作浏览器的多个窗口时,怎么做?你想过吗?

通常情况下,都只需要在一个窗口中完成任务。如果同时出现两个窗口的话,QTP就会出错,因为QTP匹配到了大于1个的窗口对象,所以它不知道究竟该对哪个具体对象进行操作了。所以,此时就要用以下这个方法,脚本如下所示:

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"

Browser("CreationTime:=1").Navigate "http://www.baidu.com"

使用以上代码,QTP就能够分辨出多个浏览器窗口了,当然,也可以使用Index或Location属性,大家可以尝试一下。同时,也可以尝试一下如何将指定的窗口关闭。

另外,当使用Browser ("CreationTime:=-1")的时候,表明当前有且仅有一个浏览器窗口,当只需要一个浏览器的时候,可以使用这个方法来作为判断依据,脚本如下所示:

objBrowser = Browser ("CreationTime:=-1").Exist (0)

If objBrowser Then

Msgbox "只存在一个浏览器窗口"

else

Msgbox "存在0个或多个浏览器窗口"

End If

(3)使用描述性编程通过遍历对象完成N个同类控件的操作。

假设有这么一个场景,页面中有几百个输入框,此时如果逐一将这几百个对象添加到对象库是不科学的,使用描述性编程则是一个明智选择。但是,也不能逐一描述,因为效率同样的低。在这种情况下,就可以用描述性编程来遍历页面中的对象,从而最终完成艰巨的任务。百度的高级搜索页面就是一个比较典型的例子,页面中有很多输入框,如图1-192所示。

图1-192

现在要对这些输入框做文章,在每个WebEdit中输入“QTP自动化测试技术领航”这段字符串,实现脚本如下:

'打开网站页面

SystemUtil.Run "C:\Program Files\Internet Explorer\IEXPLORE.EXE",_

"http://www.baidu.com/gaoji/advanced.html"

'描述对象 -- WebEdit

Set all_oEdit = Description.Create

all_oEdit("micClass").value = "WebEdit"

'为WebEdit找父对象和祖父对象,并将所有对象“包装”在一起

Set all_oEdits = Browser("micClass:=Browser").Page("micClass:=Page")._

ChildObjects(all_oEdit)

'遍历页面中的WebEdit对象,找到一个就输入一串指定的字符串

For i = 0 to all_oEdits.count - 1

Set oEdit = all_oEdits.item(i)

oEdit.Set "QTP自动化测试技术领航"

Next

'最后记得释放所有设置的对象

Set oEdit = Nothing

Set all_oEdits = Nothing

Set all_oEdit = Nothing

(4)QTP自带的网上订票系统是一个非常经典的描述性编程例子

众所周知,在QTP 里自带着一个网上订机票的网站,也就是Mercury Tour。现在一起来看一下在订票过程中何时需要使用描述性编程。

首先登录系统后,如果需要订票的话,就要先搜索航班,此时系统要求输入订票乘客的数量,假设在第一次写脚本的时侯将Passengers设置成了1,然后成功地完成了订票。然后,需要参数化乘客数量来测试订票系统,我们会发现QTP回放失败了。其根本原因在于,乘客的数量已经变化了,导致在订票时需要输入每个乘客的姓名,而在写第一个脚本的时候,只设定了一个乘客的姓名。乘客姓名的输入框是随着乘客数量的变化而动态生成的,我们不可能从对象库里得到没有添加过的对象(如果是100个乘客,那需要事先将100个乘客对应的姓名输入框添加到对象库里,显然这是不可取的)。因此,必须使用描述性编程来完成这个业务。现在,我们假设将乘客数量设定为2,如图1-193所示。

然后来看一下设定单个乘客时的脚本如下所示:

Browser("Welcome: Mercury Tours")._

Page("Book a Flight: Mercury").WebEdit("passFirst0").Set "FirstName"

Browser("Welcome: Mercury Tours")._

Page("Book a Flight: Mercury").WebEdit("passLast0").Set "LastName"

然后到对象库里看看WebEdit控件,可以看到对象的属性如图1-194所示。

图1-193
图1-194

当系统对于发生多个FirstName时,命名规则是passFirst0,passFirst1…依次类推。因此,我们现在只要通过描述性编程就可以完成动态FirstName与LastName的识别工作了。假设参数化的乘客数已经赋值给intPassNum= 3,那么在此,描述性编程脚本就该这样写:

For i = 0 to 3

Browser("Find a Flight:")._

Page("Book a Flight:").WebEdit("name:=passFirst"& i).Set "FirstName"

Browser("Find a Flight:")._

Page("Book a Flight:").WebEdit("name:=passLast"& i).Set "LastName"

Next

再举一个和这个经典例子差不多的案例,比如现在有一个订书的网站,有一个输入框可以输入想要订购的数量,输入1就会出现1个输入书名的文本框,代码是:WebEdit("name:=book1");输入2就会出现2个输入书名的文本框,代码是WebEdit("name:=book2")…同样也是依此类推。像碰到这类情况,最好的解决方案就是描述性编程,代码可以是:WebEdit("name:=book"& i)。

小结:以上这些都是对象库编程搞不定或者不适宜搞定的案例。在真实的项目中一定还会有形形色色的案例,在此无法全部列举。但是完全可以举一反三,善加利用描述性编程,从而可以出色地辅助我们完成各种自动化测试需求。

 

1.7.5 终极对决——对象库编程(OP) VS描述性编程(DP)

关于对象库编程和描述性编程的学习就要接近尾声了。临近结束之时,再一起来分析一下对象库编程和描述性编程各自的优势,也即知己知彼百战百胜。

对象库的优势。

(1)可以通过Complete Word、“F7”等多个方式进行高效编程。这个特性描述性编程没有。

(2)对象库编程有一个比较好的特性,假设脚本中引用了同一个对象10多次,这个对象的名字之前取得不是太出色,项目经理要求改名。此时不需要改10多次,只需要进入对象库,对这个对象进行更名,脚本便会批量自动更新,很高效!这个特性描述性编程也没有。

(3)对象库编程不容易打错字,因为有 Complete Word,想打错字都难。但是,描述性编程没有 Complete Word,所以,打错字是家常便饭。关键是,对于一个新测试员来说,他不可能有敏锐的分析手段,往往因为这么一个小错别字会浪费很多时间。其实只是一个错别字而已,往往最后被误解成脚本发生了错误,无论怎么调试都看不出来。

描述性编程的优势。

(1)不用维护庞大的对象库,不过需要维护庞大的代码。所以这算是优势还是劣势?请读者感悟。作者在此提一句,其实在对象库功能做得如此智能的情况下,维护好对象库不难,只要根据在“对象库”那个章节中介绍的一些法则,如命名规范等就可以管理好对象库。

(2)描述性编程可以完成一些特殊的需求(上一个小节的主讲内容)。

最后的PK结果:对象库编程获胜!

 

1.7.6 总结

描述性编程的学习全部结束了,它是一个很好、很优秀的功能,但同时也是一把双刃剑。最大的问题就是由于脚本无法维护导致自动化测试项目的失败。

通过本章的学习,希望读者不光可以掌握描述性编程的技能,更应该了解它的缺陷,不要盲目崇拜“编程”这两个字,开个玩笑的说:“描述性编程,不好惹!”

自动化测试的目的是使测试自动化起来,不是一种炫耀,本人也一再强调过:能做好自动化测试项目的自动化测试才是好的、成功的。所以,不到必不得已,请远离“描述性编程”!

在对象库编程和描述性编程的学习结束之际,也就意味着广大新人读者已经完全可以独立去写一些自动化测试脚本了,已经逐步开始有能力成为一名“QTP 自动化测试工程师”,已经彻底摆脱了录制化的QTP,这是一个里程碑!

 

知识点巩固和举一反三练习

素材:

title = Browser("百度一下,你就知道").Page("百度一下,你就知道").Object.title

Msgbox Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").GetROProperty("value")

Browser("百度一下,你就知道").Page("百度一下,你就知道").Link("关于百度").Click

一、使用基础方法描述素材中的代码。

二、使用Description.Create方法描述素材中的代码。

 

1.8 数据池(Data Table)的应用

阶段要点

• 熟悉测试数据和脚本业务分离的好处和优势。

• 学会利用Data Table 将测试数据与业务分离。

• Global Sheet与Local Sheet 的区别。

• Test DataTable VS Run-time Data Table。

• Data Table常用方法指引。

 

1.8.1 引言

作为一个QTP 自动化测试工程师,学会使用Data Table 是必不可少的。Data Table 其实和Excel非常相似,几乎可以说是“克隆”出来的。所以,读者会上手的很快。

虽然上手会比较快,但是也别小看了它,因为在自动化测试过程中,数据之间的传递是非常重要和常用的,小小的一个Data Table 可绝对是自动化测试的主力和核心组件。在前面已经学会了整个对象库的使用。那么在本章节就让我们来一起领略Data Table 是如何管理好庞大而且繁琐的测试数据的、是如何进行不同测试数据的传递的……

 

1.8.2 学会使用Data Table进行参数化

1.8.2.1 为什么要进行参数化

首先,从最简单和常见的说起,相信大家对参数化这个词非常熟悉,在本书的前面也提到过,不过并没有细致地讲解如何参数化。因为,QTP 内置的参数化功能其实在真实项目中是不会去使用的。那如何去参数化测试数据呢?答案就是利用这个Data Table,使用它配合代码来管理好繁杂的测试数据才是自动化测试的正道。接下来,让我们进入第一个实例,先来看下面这段代码:

SystemUtil.Run "www.baidu.com"

For i = 0 to 9

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "QTP自动化测试技术领航"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度搜索_搜索结果页面")._

Image("到百度首页").Click

Next

然后,图1-195是脚本对应的对象库,读者可以看一下。

图1-195

最后,我们解读一下脚本:这段脚本其实还是比较简单的。先打开一个浏览器,然后进入百度的首页,接着输入关键字“QTP自动化测试技术领航”,最后点击“百度一下”按钮。这样,百度会进入搜索匹配页面,此时便可以开始做很多测试验证。当然,这里验证省略掉了,因为这是后面章节的内容。那我们假设验证是通过的,成功匹配到了“QTP自动化测试技术领航”的一些相关信息,那么通过点击“到百度首页”这个Image对象回到首页,因为需要再一次输入测试数据,再进行N次测试,测试什么?就是测试关键字输入后点击搜索能否正确搜索到相关的信息。所以,在这里写了一个循环。这样,QTP 就能测试 10 次了,这个结果应该很可靠了吧?如果10次都通过了,那这个功能就应该没问题了。

单从表面上看,的确是!但是,同样面临一个问题,那就是在用同一个测试数据“QTP自动化测试技术领航”在做测试。所以,执行1次和执行上百次是没有什么实质性的区别的,特别像这种搜索框之类的功能点,这样的自动化测试也算是一种浪费时间的无效测试(特殊情况除外,如可靠性测试)。怎么才算有效?从手工测试的角度上来说,就是输入完全不同的测试数据,然后查看测试结果。那QTP该怎么做呢?很简单,只要把关键字输入框中Set的数据改掉就可以了,如下面这个脚本:

'启动浏览器并进入百度首页

SystemUtil.Run "www.baidu.com"

'第一次

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "QTP自动化测试技术领航"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度搜索_搜索结果页面")._

Image("到百度首页").Click

'第N次

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "谷歌"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度搜索_搜索结果页面")._

Image("到百度首页").Click

'第十次

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "最后一次了,相同的代码一共使用了10遍"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度搜索_搜索结果页面")._

Image("到百度首页").Click

上面这段代码最后完全实现了想要的效果,但是,缺点大家都已经看到了,有太多的重复内容,假设是要输入100个测试数据呢?复制、粘贴100次吗?显然不需这样,完全可以将 Set 的值进行参数化。先给出第一个解决方案,使用前面第一段代码相同的循环,但又每次输入不同的关键字,代码如下所示:

SystemUtil.Run "www.baidu.com"

For i = 0 to 9

'句1:代码唯一有改变的一句

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set DataTable.Value("关键字输入","Action1")&i

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Page("百度搜索_搜索结果页面")._

Image("到百度首页").Click

Next

我们来分析一下这个脚本,其实这段代码几乎和先前的那段代码没有两样,作者只改动了一句而已(代码里用注释标注的句1)。解决方案其实也不难,就是把每次循环的计数和测试输入组合,这样每个测试数据就都不一样了。不过,读者应该发现了吧,在这里并没有直接将测试数据明确写出来,取而代之的是 Data Table.Value("关键字输入","Action1")这句话。这个就是本章节介绍的参数化,通过DataTable参数化。

作者把测试数据封装到了Data Table.Value("关键字输入","Action1")里,如图1-196所示。

图1-196

如图1-196 所示,这个就是QTP 内置的Data Talbe 界面,可以在这里输入一些数据。把测试数据“QTP自动化测试技术领航”输入到了A1这个单元格里。这样做有什么好处?首先,一定知道现在所做的事情的意义和意图。其实从某种角度上讲,虽然操作很简便,但是,我们是在做封装的动作,将测试数据独立出来,并封装到一个容器里,以后可以供脚本调用。为什么要封装并且要把测试数据独立出来存放到一个储存的地方?试想一下,如果不进行测试数据封装会有什么后果。比如脚本里有100处地方需要输入这个测试数据,如果突然有一天测试需求变化了,不再需要输入这个关键字,需要换另一种测试数据进行输入,因为需要修改100处地方!如果此时测试数据和脚本是分离的,那我们只需要在A1这个单元格修改1次就可以了!1:100哪个划算,相信读者和本人一样清楚!到此,也引出了自动化测试的一个重要理念:测试数据和脚本业务的抽离。当然,将测试数据剥离出脚本的方法有很多种,在这里只介绍如何利用QTP 的Data Table 进行测试数据分离。

1.8.2.2 如何具体操作

在上个小节中,已经介绍了将测试数据与脚本业务分离的知识,并且读者也看到了数据分离后的情况。那么接下来,一步步地介绍具体该如何去完成数据与业务相分离的操作。在开始前,首先一起来看一下Data Table 的原始情况,如图1-197 所示。

如图1-197所示,可以看到当前一共有两个Sheet,它们分别是Global和Action1。接下来,暂且不对Global“做文章”,只对Action1做文章。那么,操作步骤正式开始。

Step1,选中“Action1”这个 Sheet,将鼠标光标移动至 Column“A”,然后双击,如图1-198所示。

图1-197
图1-198

Step2,待弹出Change Parameter Name 窗口后,任意输入一个name 值,这个值将会变成A列的列名。在这里,作者输入了“演示”这两个字,最后点击OK,如图1-199(注:本步骤可以省略,这样的话,列名等于A)。

Step3,到此为止,已经完成了一大半的操作,已经为测试数据建好了一个“家”,以后它们完全可以搬到这个位置“居住”。接下来,在对应“演示”这列的第一行交叉处写入一个值,这个值就是测试数据,如图1-200所示。

图1-199
图1-200

如图1-200所示,测试数据部分的工作已经完成了,最后一步就是如何在脚本中引用了。在此,介绍第一个Data Table 语法——“引用单元格”,如下:

DataTable.Value (ParameterID , SheetID)

DataTable (ParameterID , SheetID)

语法分析。

Data Table 本身就是一个Object,它可以点出一个Value 方法,然后就可以通过在后面括号中设置参数来定位到单元格的值了。参数一共有两个,第一个参数“ParameterID”指代列名(在这个实例中列名是“演示”),第二个参数“SheetID”则指代Sheet的名字。

在这里,Value方法可以省略,效果也是一样的。

Step4,最后一步,完成以下脚本成功引用到单元格,使得百度搜索框可以输入单元格中的测试数据,脚本如下所示:

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set DataTable.Value("演示","Action1")

小提示

当DataTable的列数超过2列时,在输入“DataTable”(以后会自动出现代码提示,列出当前Sheet下的所有列的列名。Data Table.Value不适用),如图1-201和图1-202所示。

图1-201
图1-202

小结:

这是一个最基本的例子,只有学会了这个基本实例,读者才能继续后面的学习,后面的一些内容是万变不离其宗的,核心的东西是一致的。

1.8.2.3 Global Sheet VS Local Sheet

如果有这样一个测试需求——进行3次百度搜索的业务流程,但是每次输入的关键字必须不一样,此时QTP该怎么完成?请看参考答案,见如下脚本:

'打开网页 -- 第1次

SystemUtil.Run "www.baidu.com"

'输入关键字“test1”并点击搜索

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "test1"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

'关闭网页

Browser("百度一下,你就知道").Close

'相同代码 -- 第2次

SystemUtil.Run "www.baidu.com"

'只变更测试数据

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "test2"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Close

'相同代码 --第3次

SystemUtil.Run "www.baidu.com"

'只变更测试数据

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "test3"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

Browser("百度一下,你就知道").Close

正确答案已经公布了,运行成功,自动化测试脚本成功实现!但是,这就是我们想要的吗?但是如果要输入 10 次不同的测试数据呢?甚至于上百次呢?难道也要跟着复制→粘贴100次吗?那这脚本该有多庞大啊!

有什么更好的解决方法吗?答案是肯定的,那就是接下来要介绍的Global Sheet。在上一个小节中,所讲的实例是用Local Sheet(Action1)来完成的,那么接下来就来看下面这段代码,看看用Global Sheet是否能够圆满完成任务,脚本如下所示:

'打开百度首页

SystemUtil.Run "www.baidu.com"

'将DataTable里的值传递给一个变量

testData = DataTable.Value("关键字输入","Global")

'使用该变量,并将其填入关键字输入框

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set testData

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

'关闭网页

Browser("百度一下,你就知道").Close

该脚本仅用了几行代码就能完成3次业务循环吗?而且还要用不同的数据?别着急,我们来运行一下该脚本,看一下运行结果,是否自动化测试圆满完成了,如图1-203所示。

图1-203是QTP 的另一个重要模块“测试报告(Test Results)”,这个在后面的章节会详细介绍,这里读者只需要看运行结果就行了。我们可以看到,QTP运行了3次迭代,这就证明了QTP的确进行了3次业务循环。那接下来,再来证明这3次业务循环所用的测试数据都是完全不同的,如图1-204所示。

图1-203
图1-204

如图1-204 所示,点击Run-Time Data Table 以后,可以看到脚本在运行过程中所使用的所有数据记录,分别是test1、test2、test3。到此,大家应该没有任何疑问了吧?的确是运行了3次业务,切实地输入了各不相同的测试数据。想知道这些测试数据哪里来的吗?答案现在正式揭晓,如图1-205所示。

图1-205

有没有似曾相识的感觉?在上一个小节中的实例就已经和它打过交道了,它就是QTP 的Data Table。请大家注意当前脚本使用的是Global Sheet 而不是Local Sheet!在“关键字输入”这一列中输入了3 行测试数据,这就是实际运行时输入的数据。

测试数据是怎么来的,我们已经搞清楚了。但是相信读者现在一定还有另外一个疑问,那就是QTP为什么会执行3次,脚本中并没有做任何循环!这就要引出本小节内容的第一个知识点了。

1.Global Sheet 是一个全局变量!有几行数据,程序就要回放几次

所以,这也就很清楚地解释了为什么QTP 运行了3 次,就是因为当前的Global Sheet 中有3行测试数据。第1次执行使用第一行数据test1,第二次执行使用第二行数据test2,第三次执行使用第三行数据test3,依此可以一直类推下去。

现在设置了 3 行测试数据,这些数据不一定是我们每次都需要的,那该怎么办?删除它们?等需要了再添加?那多麻烦。QTP 提供了一个很有用的功能,那就是Data Table iterations设置,先来认识一下它,调用它的方法如下。

QTP 上方菜单栏→File→Settings→Run 打开后的结果如图1-206所示。

图1-206

如图1-206 所示,这就是Data Table iterations设置界面,默认选中的是Run on all rows (图中标记2),即Data Table中有几行数据就运行几次,刚才的实例根据业务要求设置了3行数据,所以它会去运行3次。在很多情况下,自动化测试数据只需要1个,那么此时就可以选中Run one iteration only这个选项(图中标记1),这样就完全可以不必去删除本次不会用到的业务数据了。最后一个选项(图中标记3)叫Run fromrow X to row Y,这个也非常好理解,就是设置一个范围,QTP就会根据设定的范围进行迭代运行,当然,千万不要将范围超出最大的范围(在本实例中最大范围是3)。到此,就要引出另一个知识点了。

2.Global Sheet 这个全局变量是受Data Table iterations控制的

那么,读者要问了:“现在Global Sheet 和Local Sheet 都通过实例讲解过了,那它们之间有什么区别呢?”让我们再次引出另一个知识点。

3.Local Sheet是个局部变量,它并不受Data Table iterations控制,无论有多少行数据,它只运行一次(前提是Global Sheet没有数据,或只有一行数据,或设置为只运行一次)

让我们来看一个实例,把Global Sheet 的数据都清空,然后在Local Sheet 中建立3 行测试数据,如图1-207和图1-208所示。

图1-207
图1-208

然后,仍然复用之前的脚本,唯一更改的一处就是把引用 Globl Sheet 改成引用 Local Sheet,代码如下所示:

SystemUtil.Run "www.baidu.com"

'唯一的区别就是把Global改成了Action1

testData = DataTable.Value("关键字输入","Action1")

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("关键字输入框").Set testData

Browser("百度一下,你就知道").Page("百度一下,你就知道").WebButton("百度一下").Click

Browser("百度一下,你就知道").Close

然后,运行脚本,来看一下尽管Local Sheet 中有3 行测试数据,但是是否只运行了一次,如图1-209所示。

图1-209

很明显,图1-209已经给出了结果!通过这两个实例,已经明确了它们之间各自的用处。但是呢,Data Table的确是QTP的一个难点,即使Global Sheet 没有数据,仍然可以通过别的方式(代码控制的方式排除在外)去执行Local Sheet 下的所有行。在Test Flow(后续章节会介绍)里反击Action 后可以进入Action 的一些相关设置,如图1-210和图1-211所示。

如图1-211,界面很熟悉吧?它和Global的Data Table iterations设置界面相似,在这里选中Run on all rows 就可以执行Local Sheet 下的所有测试数据了。虽然都是执行所有行数据,不过它们的区别还是很大的,先看一下执行结果,如图1-212(脚本略)。

图1-209
图1-211
图1-212

光看一张图可不行,绝对不够直观,再回过头看之前Global的那张图,如图1-213所示。

图1-213

这样很直观了吧?区别相当明显,Local Sheet 执行了3 次自身Action 的迭代,而Global Sheet就相当于执行了3次脚本,这之间可是有着天壤之别的!至于这天囊之别的细节之处不是一本书能够细致介绍的,需要读者亲自实践、细细品味,结合自己的项目多思考。

在最后,还总结了一些Global和Local之间的逻辑规则,大致为以下几点。

Global 不止一行数据(设置为 Run on all rows,以下都是……),Action 也设置为Run on all rows(以下都是……)且假设双方都具有3 行测试数据,此时Global和Action的每行都要运行且同步运行(即Global在取第2行数据时,Action也对应地取它的第二行数据)。

当Global 不止一行数据且Global 的行数大于Action 的行数,那么当Action 执行到最后一行后,Global以后所执行的行数,Action都用它的最后一行数据去补,比如Action的最后一行测试数据是test3,那么即使Global执行到了100行,也一直对应的是Action中test3的这一行数据。

引用上面的条件,如果Global 的行数小于Action的行数的话,Action 就执行不到最后一行了。

 

1.8.3 Test DataTable VS Run-time Data Table

这个标题很熟悉吧,在本书的前面几个章节,介绍过Test Object 和Run-time Object。在这里,我们又和Test…以及Run-time…见面了。回顾一下,Test Object 是什么意思?就是固定在测试对象库里的测试对象。那么Run-time Object 呢?就是程序运行时实际的测试对象。那么在这里Test DataTable和Run-time DataTable 的理念完全是借鉴它们的。先来看一下TestData Table 和Run-time Data Table 之间的区别和含义。

Test Data Table——在Data table 里事先准备好的、固定的测试数据,它是一组静态数据,是由自动化测试工程师人为事先填写进去的。

Run-time Data Table——在QTP 执行过程中,将测试数据填写到Data table里,QTP运行结束,测试数据就消失(不会保存在Data table 里),但是可以在测试报告中看到它。

先来看一下Test Data Table,这个就相当简单了,并且之前就已经全面地做过实例(Global Sheet 和 Local Sheet),可以手工在 Data table 中设置一些测试数据。主要来看看 Run-time Data Table究竟是怎么回事。

我们试想一下,现在有一个注册的业务需要进行自动化测试。因为自动化测试有模块化和细分化的原则,所以,需要把这个业务拆成两个脚本,第一个脚本主要做注册的操作。而大家都知道通常现在的任何网站都会在注册后进入另一个验证界面,往往要验证一些基本信息,比如,确认你填写的用户名、生日、住址等是否正确。所以,把这个验证的业务过程封装到第二个脚本中去。那么问题就来了,如果一个测试业务由两个脚本组成,那么它们之间的数据中转该如何进行?即将第一个脚本中填写的注册信息放到第二个脚本中去验证。此时,通常情况下有两个比较好的方法,第一个就是通过EOM转出数据,这个是后续章节的内容,这里不多做阐述。而另一个好方法就是利用QTP自带的Data table,方法与实现步骤如下(假设以注册举例,只在注册后的验证界面中校验用户名这个数据)。

(1)填写完所有必填项,并使用GetRoProperty来获取已填写的用户名。

(2)将这个动态的获取到的值动态地传入Global Sheet 的某个指定列中。

(3)在第二个脚本(校验注册信息的这个页面)中动态读取这个值并做判断校验。

(4)脚本运行完毕,Run-time 数据消失,不过可以通过Test Report 来查看脚本在运行时使用过的所有测试数据。

那么接下来就来做一个实例,需完成如下业务。

(1)进入百度首页。

(2)在搜索框中输入“QTP自动化测试技术领航”字样。

(3)点击“百度一下”按钮。

(4)校验在搜索结果页面中的搜索框中是否保留了刚才输入的字样。

在看到这个业务后,先进行业务分析,并大致给出一个实现思路,步骤如下所示。

脚本1。

(1)进入百度首页。

(2)在搜索框中输入“QTP自动化测试技术领航”字样。

(3)使用GetRoProperty 去获取搜索框中刚才输入的字样,并传入Global Sheet 的指定列中。

注意

在这里读者肯定要问,为什么不直接把“QTP自动化测试技术领航”字样传入Global Sheet,而要多一个步骤通过GetRoProperty去获取?因为,如果你直接传入数据,就少了一个验证是否成功输入到搜索框中的过程了,这样的自动化测试是不可靠的。

脚本2。

(4)读取Global Sheet 中的Run-time Data。

(5)获取搜索结果页面中的搜索框的值,假设为CheckValue。

(6)将Run-time Data 与CheckValue 做比较。

最后,通过上述分解步骤完成脚本如下:

脚本1:

SystemUtil.Run "www.baidu.com"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").Set "QTP自动化测试技术领航"

Run_Time = Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("关键字输入框").GetROProperty("value")

'将Run_Time传入Global Sheet指定列

DataTable.Value("Runtime_Data","Global") = Run_Time

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebButton("百度一下").Click

图1-214 就是设置Global Sheet 中的列。

由图1-214可以看到,这个单元格里是没有数据的。接下来继续看看脚本2。

脚本2:

Run_Time = DataTable.Value("Runtime_Data","Global")

CheckValue = Browser("百度一下,你就知道").Page("百度搜索结果页面")._

WebEdit("结果页面_关键字输入框").GetROProperty("value")

If CheckValue = Run_Time Then

else

msgbox "Passed"

msgbox "Failed"

End If

最后就是将脚本1和2组合在一起的脚本X了,这里不贴出这部分脚本,因为这将是下一个章节的学习内容。

从脚本2中可以看到,如果最终验证通过了,会弹出对话框,显示“Passed”。那么,来看一下运行结果到底是什么呢?最终是否验证成功呢?如图1-215所示。

我们可以看到,自动化测试圆满成功!接下来,让我们见证是否Run-time Data的生命周期相当的短,QTP运行完毕就会消失,如图1-216所示。

图1-214
图1-215
图1-216

再让我们看看,QTP运行期间是否有数据被填写到Runtime_Data这个列中,如图1-217所示。

最后,让我们验证是否可以在QTP的Test Report中看到运行时所用到的数据,如图1-218所示。

图1-217
图1-218

验证全部结束,一切都和叙述得完全一致!到此,相信读者都已经对 QTP 的 Datatable有了更深刻的认知。

细心的读者一定注意到了,好像这个小节中都在使用Global Sheet。所以,相信读者一定会有疑问“为什么不能用 LocalSheet?”因为针对将不同脚本组合成一个业务脚本的这种形式,用Local Sheet 是不能将值传递给另一个脚本的,只有Global Sheet 才是被共享的!就算不是用组合脚本这种形式,把所有的业务写在一个脚本中,用Action划分,那为了共享不同Action 间的数据,仍然要使用Global Sheet。

至于如何把两个脚本嵌入到一个脚本中,这是后续章节的内容。

 

1.8.4 用好Data Table对象使脚本更加灵活

因为QTP的Data Table是一个保留对象,所以,Mercury在实现此功能的时候为它写了很多的实用方法。使用好这些实用的方法,可以让我们的脚本更加灵活、多变。作者接下来列举一些常用的方法供读者参考:

1.动态地在Data Table中添加新列并赋值

DataTable.GlobalSheet.AddParameter "Column1","Value1"

DataTable.GlobalSheet.AddParameter "Column2","Value2"

DataTable.LocalSheet.AddParameter "Column3","Value3"

运行结果图1-219和图1-220所示。

图1-219
图1-220

2.动态地在Data Table里增加新行并赋值

DataTable.GetSheet("Action1").SetCurrentRow ( 2 ) '句1

DataTable.Value("Column4","Action1") = "Row2"

'或者也可以是:

DataTable.Value(1,2) = "Row2"

运行结果图1-221所示。

必须使用“句1”才能新增行,不然会被原值替代。因为QTP在GetCurrentRow这个过程结束后仍然处于第1行。

运行结果如图1-222所示。

图1-221
图1-222

如图1-222所示,我们可以看到,“Row2”这个值被赋到了第一行中。

3.动态获取Data Table中指定列的值

GetValue1 = DataTable("Column5","Global")

msgbox GetValue1

GetValue2 = DataTable("Column6","Action1")

msgbox GetValue2

以上两种其实我们已经在之前的实例中都用过了,还有一种更加简单的写法,在上面也已经用过,就是直接输入列的序号,比如引用第一列就直接输入 1,依此类推,完全不用去关心“列”具体叫什么名字,代码如下所示:

GetValue3 = DataTable(1, "Action1")

msgbox GetValue3

也正是因为这样,完全可以引申出另一个应用:循环读取Action1的N列,代码如下所示:

For i = 1 To N

msgbox DataTable(i, "Action1")

Next

如果有两个Action,分别是Action1和Action2,要想使它们在获取的时候保持读取的行数一致,可以使用下面两种方法:

'方法1:直接定位Action2的行。

DataTable.GetSheet("Action2").SetCurrentRow(2)

'方法2:使用变量传递保持行数一致

CurrentRow = DataTable.GetSheet("Action1").GetCurrentRow

DataTable.GetSheet("Action2").SetCurrentRow(CurrentRow)

4.动态获取Data Table中指定行的值

getValueByRow = DataTable.GetSheet("Action1").GetParameter("Column7").ValueByRow(2)

msgbox getValueByRow

5.动态获取Data Table中当前行和设置当前行

'1、获取当前行

CurrentRow = DataTable.GetSheet("Action1").GetCurrentRow

'msgbox CurrentRow

'2、设置当前行

DataTable.GetSheet("Action2").SetCurrentRow(5)

'注意:增加Action2的列数跟行数的计算没有任何关系

DataTable.GetSheet("Action2").AddParameter "Column8","Value4"

CurrentRow2 = DataTable.GetSheet("Action2").GetCurrentRow

'msgbox CurrentRow2

6.获取得到Data Table总行数的命令

AllRowCount = DataTable.GetSheet("Action1").GetRowCount

msgbox AllRowCount

 

1.8.5 总结

Data Table 是QTP的一个亮点环节,但是也是QTP的一个难点。比如Global Sheet和Local Sheet的区别以及它们的逻辑应用。还比如在1.8.4小节中介绍的一些关于Data Table的应用,只是列举了一些个人认为比较常用的,其实还有很多方法经常会被使用到。不过读者完全不必担心,很多东西在QTP强大的“F1”里都有参考资料和示例,包括举例的那些方法在F1里一个都没有漏掉!不光要用好帮助文档,最终读者要做到的是,能够看着示例举一反三,随意地应用到项目中去。下面就是关于Data Table的示例截图,如图1-223所示。

比如点击图1-223 中的GetCurrent RowMethod 链接就能够进入到该方法的具体示例,如图1-224所示。

图1-223
图1-224

 

知识点巩固和举一反三练习

一、查阅“兵书”,根据下述要求写出相应的代码。

(1)删除QTP的Action1这个Sheet。

(2)将某个Excel表格全部导入QTP的Datatable中。

二、统计QTP当前Datatable的Sheet总数,并将该数据填入Global Sheet的“1行1列”。

 

1.9 操作模块(Actions)

阶段要点

• Action的3 种类型。

• 关于Action 操作的一些小技巧。

• Call Action 的3 种方式和Split Action。

 

1.9.1 使用Actions来控制好业务流

已经学习到“操作模块-Actions”章节了,从本书的第一章开始到现在,本人多次强调了自动化测试的成功之道很大一部分取决于如何维护,要在还没有正式测试立项之前就考虑到维护的问题。当然,为了更好地做好维护脚本的工作,我们是有比较好的经验可学习的,就比如之前反复强调的“脚本模块化、细分化”,这些自动化测试规则并不是本人的原创,它们都是测试前辈们总结出的经验,所以非常值得我们借鉴,而且这些优秀的思想绝对不只是QTP一个自动化测试工具能享有它,它面向的是自动化测试,而不是工具!

在之前的章节中虽然多次提到了“脚本模块化和细分化”,但是究竟如何去做呢?我们并不知道!因此,在本章节就和读者开始基于“脚本模块化和细分化”进行探讨。因为本书是一本QTP方面的技术书籍,因此,始终围绕QTP这个自动化测试工具。所以,本章节的内容就是论述关于QTP的“脚本模块化和细分化”。怎么做?如何做?

从QTP10.0开始,有一个功能可以方便地管理和驱动所开发的测试脚本,这个功能完全就是针对“脚本模块化和细分化”这个伟大的思想而开发的,先来认识下这位朋友,如图1-225所示。

读者在看了这个小窗口后是不是有种似曾相识的感觉呢?在上一个章节“Datatable”中其实已经见到过它了,QTP10.0 默认情况是显示这个小窗口的,如果不小心关掉了,只要依次点击QTP 上方菜单栏→View→Test Flow,就可以重新显示了,这个小窗口还可以被拖动成一个浮动窗口任意摆放位置,也可以进行自动隐藏(点击右上角x键左边的按钮),在这里就不多作介绍了。你们还记得下面这张图吗?如图1-226所示。

图1-225
图1-226

当时在介绍控制 Action 的 Datatable 迭代次数时,就是在此处设置的。这里还有很多比较实用的功能会介绍到。接下来,先布置好一个自动化测试业务流,如图1-227所示。

如图1-227 所示,这就是一个业务的Test Flow(测试流程),我们可以看到它是非常有序的。让我们来介绍一下这个测试流:作者的设计思想是将所有功能模块化,即产出一个个独立的功能子脚本。然后组合成一个个不同的业务脚本,在图1-227中可以看到, QTP_TestFlow是当前脚本的名称,MainAction是这个脚本的一个 Action(如果有多个 Action,与这个 Action 在同一个树形结构下),在这里只需要有一个Action即可。它是一个主控 Action,用来收纳所有业务所需要的子脚本,这些业务子脚本就存在于图中MainAction的结构树下,它们属于MainAction的子结构,这个非常好理解。MainAction在运行时会依次根据当前排列的顺序执行它们,至于这个顺序是怎么来的?是在主控脚本中设置或直接写代码引用的,这个在后面的小节中会讲到,这里暂时略过。然后我们可以看到,子脚本的名字也是比较有特色的,从名字上就能很直观地反映该脚本大致是干什么的。这个当然不可能是QTP自动生成的,很明显是本人有意更名的。接下来看看到底是如何改名的。只需要将鼠标光标移动到某个Action上,点击右键,然后在弹出的菜单中选择Action Properties就可以了,如图1-228 所示。

图1-227

点击以后,可以进入图1-229所示的界面。

图1-228
图1-229

这个窗口下共有5 个Tab,更名的操作就是在默认的第一个General Tab 中进行的。不过本人无论如何都无法给这个Action改名的,为什么?因为这个Action是从外部调用过来的,也只有外部调用过来的Action 才会有5 个Tab,多出了一个External Action。在这里就不对这些 Tab 里的功能多做介绍了,读者如有兴趣可以自行研究。那么,我们来改一个非外部的Action Name 试试,同样是右键单击MainAction,然后在弹出的菜单中选择Action Properties,进入Action Properties 设置窗口,如图1-230 所示。

将Name改成Main(图略),最后点击确定,Test Flow就会随之变化了,如图1-231所示。

图1-230
图1-231

在这里除了更改Action Name 之外,还有一个小知识点也比较重要,重新看下图1-230,在Action Properties的左下方有一个Reusable action 控件,只有勾选上以后,脚本才能被共享和调用,所以准备成为“被调用的外部脚本”的子脚本务必勾选上。其实就是在这个窗口设置的,往往读者都不知道外部脚本调用失败就是因为这个小控件引起的。就是外部子脚本被调用以后显示的名字比较奇怪,似乎不只是ActionName。的确是这样的,在被调用后,子脚本会自动显示为Action Name [Test Name],因为这样会显得非常的直观!

右键单击Action的Name,除了更改名称之外,其他的一些操作也比较实用,如Object Repository-通过 Action 打开相对应的对象库,Run from Action-只运行指定 Action,Run to Action-从第一个Action运行到指定Action等。

最后,列举并总结了关于 Action 的一些概念,这些知识有助于开展后面小节的学习, Action共分3种类型。

非重用型:只能被存储它的Test 调用,且只能被调用一次。

重用型:可以多次被存储它的Test或别的Test调用。

外部型:一个存储在别的Test中的可重用型Action,只能在调用它的Test中“只读”。

 

1.9.2 Call Action的3种方式

在前面所讲的内容中,已经看到了一个现象,那就是一个主脚本同时调用多个子脚本。从这小节开始,就让我们一起动手做一做。在QTP中,对于Action的操作一共分4种,其中3种是一个Call的行为,还有一种是切分。在这里,先来介绍所有Call的行为。先介绍第一个“Call to Existing Action”,在上一个小节里做的实验也是基于这个Call 完成的。先来看一下它的位置,如图1-232所示。

图1-232

如图1-232所示,在QTP的快捷栏中,点击“小三角”就能看到个选项,它们分别是。

Call to New Action。

Call to Copy of Action。

Call to Existing Action。

1.Call to Existing Action

当前运用到的是第3个选项(在后面介绍其他2个选项时将不再重复GPRS定位),点击这个选项,如图1-233所示。

如图1-233所示,点击后会弹出这个窗口。在此,基本操作就不介绍了,相信广大读者一定可以很快运用,主要就是讲解Action下拉框,假设一个脚本有两个或以上的Action,可以在这里任意选择其中一个Action,每次只能选择一个。现在选中一个事先准备好的外部脚本,如图1-234所示。

图1-233
图1-234

如图1-234所示,已经选中了脚本,并且选择了Action<LaunchProgram>(其实是别无选择,只有这么一个Action),这里又要注意一个地方,那就是最下方的两个选项。

At the end of the test。

After the current step。

如果选择了前者,在点击了OK以后,被调用的脚本Action是当前Test的一个Action;若选择后者,被调用的Action则属于当前Action的一个步骤,即成为了当前Action的一个子 Action。所以,在这里需要选择的是后者,最后点击 OK,看看接下来会发生什么样的状况,如图1-235所示。

如图1-235所示,当点击OK以后,QTP会弹出一个窗口,这窗口干什么用的?说简单点就是点击Yes设置成相对路径,点击No设置成绝对路径。尝试着点击Yes,如图1-236所示。

图1-235
图1-236

我们可以看到,在点击 Yes 以后,这个被调用的外部脚本<LaunchProgram>被设置了相对路径,在文本框里只显示脚本名称,不显示具体路径,最后再次点击OK,如图1-237所示。

图1-237

如图1-237所示,整个过程完毕,在代码区域自动生成了一行代码:

RunAction "LanuchBaidu [LaunchProgram]", oneIteration

这句代码代表的就是我们的操作,其实等读者以后熟悉以后,直接写代码就可以了。最后跟了一个参数“oneIteration”,意味进行一次迭代,这是默认的,一般情况下,没必要去改它,除非有一些特殊需求,在这里就不多作阐述了。与此同时,也可以看到左侧的Test Flow窗口中也有变化,在 Action1 下面已经嵌入了调用的Action。最后,Call Action 的操作还会带来一个关键的变化,如图1-238所示。

图1-238

通过图1-238可以看到,QTP的Datatable中多了一个Sheet。没错,在调用了Action以后,QTP会自动添加该Action的Sheet。

第一个 Action 搞定了,接下来你完全可以搞定 N个Action。在这里还要分享一个小经验,为什么推崇由主控脚本控制不同Action?还有一个最根本的原因就是,比如子脚本A发生了变化,它又被 100 个脚本调用过,如果不是使用Call外部Action的方式,那么就要修改100个脚本,但是现在已经完全解决了这个问题,只需要修改子脚本A,所有调用它的主控脚本都会随之改变,极大地提高了效率,缩小了自动化测试的维护成本!读者可以自行实验,亲身感受一番。

2.Call to New Action

在有了前面这个实例的基础后,其实其他两个选项在操作上都是大同小异的,区别就在于它们的性质不同。Call to New Action,别看这个名字挺复杂的,其实它就是New a Action,可以基于Test新建很多1级Action,也可以基于1级Action新建很多2级、3级Action,同样的,在新建任何Action以后,QTP的Datatable会自动生成一个Sheet,如果将Action的名称改掉,该Sheet也随之发生改变,就是这么简单!

3.Call to Copy of Action

Call to Copy of Action 其实和Call to Existing Action非常相似,它们之间区别在于,它只是把外部Action的对象库、代码等复制了过来(当然,同样也会在Datatable中增加Sheet),但是它失去了“改子脚本变化主控脚本的功能”,其实原理也很简单,读者一试便知,在Call to Copy of Action的时候,QTP是不会提示是否设置相对路径的。另外,Copy 过来的 Action可以编辑,而Call Existing Action 过来的脚本是只读状态。

最后,无论是以上任意一种方式,可以通过图1-239中的位置进行脚本间的切换和修改(属于Call ExistingAction的脚本除外)。

图1-239

 

1.9.3 Action的切分

QTP 提供了Split Action这个功能,它是挺实用的,可以提高工作效率。下面了解这个功能,一起来切分图1-240中的脚本实例。

Purpose(目的):将当前脚本切分为两个脚本:<LaunchBaidu>和<CloseBaidu>。

Step1,选择要开始切分的位置,在此点击第2行代码句首,只有这样Split Action 按钮才生效。

Step2,点击Split Action,点击后的效果如图1-241所示。

Step3,在这里可以选择要将Action切分成互相独立的(Independent of each other)还是嵌套形式的(Nested),默认选择的是前者,然后分别给两个 Action 命名,分别是<LaunchBaidu>和<CloseBaidu>,最后点击OK,点击后的效果如图1-242所示。

如图1-242 所示,我们看到Action 已经被切分成两半了,左侧的Test Flow窗口里分别显示了切分后的Action,而<LaunchBaidu>这个Action里也绝对不会有<CloseBaidu>的代码,再看看Datatable的情况,如图1-243所示。

图1-240
图1-241
图1-242
图1-243

结果很明显,Datatable的Sheet也被成功切分为了两半!实验宣告成功!这里需要注意,每次做切分操作只能切分成2份,无法再切分得更多了,如果有需求的话只能多做几次Split Action操作。

 

1.9.4 总结

总体来说,QTP Action 的知识点并不算是特别多,但是Action 是一直要用的一个功能。另外,作者个人觉得,Action 的难点在于Test Flow的组织和排列,这其中牵扯很多实际项目中的测试逻辑。关于这方面的经验,只能通过不断的历练去积累,不是一本书能够概括的。

 

知识点巩固和举一反三练习

一、尝试脚本A中调用不可重用的脚本B。看看结果会如何!

 

1.10 QTP的验证点与测试报告

阶段要点

• 了解验证点在自动化测试中的重要性。

• Spy可以在做验证点时起到很好的作用。

• QTP 自带验证点函数CheckProperty。

• 自定义验证点。

• 自定义验证点-HTML 模式。

 

1.10.1 自动化测试的有效性取决于验证点的质量

在自动化测试过程中,测试结果验证是最后一道关卡。前面所学的知识都只是使用QTP操控我们的业务。那么,在这些业务顺利按照轨迹行动以后,就该进行最后的“总结”了。“总结”什么?当然不是总结前面所学的知识点……这里的“总结”就是检查,最后一道关卡就是利用QTP去检查、去验证之前所做的操作的正确性和预期性(即自动化测试用例的预期结果部分)。

在本章节中,将会学到这最后一道关卡的技能,它分为和包括两项。

如何使用QTP 做一系列的验证。

如何查看测试报告,从而判断自动化测试用例的预期结果正确与否。

 

1.10.2 侦探Jack再度登场

如图1-244所示。

图1-244

问:“在做手工功能测试时是如何验证【百度搜索框】这个功能是否好用的?是否可以正确地输入各类测试数据(字符串)的?”

答:“在【百度搜索框】中输入测试数据【QTP 自动化测试技术领航】,然后看其是否可以正常输入!”

没错,在手工测试中,所做的验证功能通常以观察去判别。那么,当我们无人值守自动化测试时,如何才能使计算机代替观察呢?如何相信 QTP 自动执行的结果是可靠的呢?在没有开始学习本章节之前,我们根本不敢说自动化测试是可靠的,即使在这个文本框中输入了字符串,又如何敢肯定地说:“所输入的测试数据一定成功键入了!”

该怎么办?如何让QTP代表我们的观察?谜底是——透彻地利用UI对象的属性值,一旦获得有效且具有威慑力的属性值,就完全有理由敢肯定自动化测试是可靠的测试。

验证点有很多,本章节以最大众的UI对象为例,其他诸如数据库验证等不会再此涉及!

“属性”,好熟悉的两个字!没错,在前面的章节学习中就早已把这两个字与QTP和自动化测试关联起来了。

怎么获得属性?万变不离其宗,我们要再度请出 QTP 风云榜冠军得主——Mr. Spy了(绰号:侦探Jack)!

相信学到这章节,大家早已经熟悉它了。那么,操作步骤就省略了,本人引导性地为读者抓取第一个关键属性,目的是为了让上面这个实例中的自动化测试成为一个可靠的行为,如图1-245所示。

图1-245

如图1-245所示,在茫茫“属性”海中,通过不懈努力终于找到了一个关键属性‘value’。这个属性足以代替我们的观察来证明测试数据被成功输入到文本框了。为什么?在下一个小节介绍。

最后,在本小节末,建议读者还是好好研究一下图1-245,可以看到当前窗口是封装属性窗口。本人从来就没有说过,旁边的自身接口属性窗口中的属性没有可利用的关键属性,也从没说过除了‘value’就一定没有其他可利用的属性了。请读者集思广益,去尝试找到更多的属性,利用它们完成实例。任何属性都可能成为“关键先生”,Impossible is nothing!

 

1.10.3 抛弃工具的使用,请使用QTP验证点函数

1.10.3.1 请抛弃QTP 自带的验证点功能

图1-246是QTP自带的检查点“功能”。它只是一项功能,尝试着随意打开一个功能点(Standard Checkpoint)看看,如图1-247 所示。

图1-246
图1-247

如图1-247所示,好复杂的功能,包括图1-246中,为什么有的功能是可以选择的,而有的功能却是灰色的,不能点击的呢?什么原理?实在不想去研究这些,因为再研究下去,我们将永远摆脱不了QTP录制模式!当你翻开这本书的第一页起,我们就有一个共同的目标“编写QTP自动化测试脚本”!下面,一起开始编写第一个检查点、验证点代码!这才是我们要做的!

1.10.3.2 使用QTP“原装”验证点函数进行一切检查工作

首先,揭开之前未解的一个小谜底。为什么获得‘value’这个属性值可以帮助我们实现QTP代替观察。原理其实挺简单,并且也很好理解,说的通俗点,从观察的角度上讲,只要我们看到测试数据嵌入在文本框里那就说明输入成功了。那么从观察(QTP代码)的角度上来讲,虽然我们看不到,但可以通过获得文本框的value值来判断测试数据是否成功输入,如果获取到的这个value值等于“QTP自动化测试技术领航”,那就证明了测试数据输入成功了。那么知道了大致的原理后,我们就来看一下具体如何实现吧,如图1-248所示。

图1-248

如图1-248所示,在第2行代码中,在最后一个子对象(也就是要验证的文本框对象)后面敲击“点”键,QTP 会进行代码提示,会显示出很多 QTP 已经封装好的方法(关于这点,在本书之前的内容中就已经介绍过了),其中第二项就是目前要隆重推介的QTP“原装”的检查点、验证点方法-CheckProperty方法。如何使用呢?如下:

---语法部分---

object.CheckProperty (PropertyName, PropertyValue, [TimeOut])

作者翻译:对象.CheckProperty方法(参数“属性名”, 参数“属性值”, 非必填项“延时”)。

---详解部分---

语法的前半段还是比较好理解的,这里主要介绍括号里的参数设置部分。

PropertyName:要检查的属性名,在本实例中是‘value’。

PropertyValue:预期结果值,在本实例中预期结果是“QTP 自动化测试技术领航”,如果最后检查完毕,发现不符合预期,则会返回False,并引入QTP测试报告;反之,则返回True,并在测试报告中以Passed显示。

TimeOut:单位是 milliseconds,可以不填,不填则代码瞬间验证结束,如果设置成5000的话,则会等待5秒钟。第1秒如果没验证对没关系,只要在5秒内验证对就算对。

---代码部分---

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").Set "QTP自动化测试技术领航"

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").CheckProperty "value","QTP自动化测试技术领航"

上面这段代码的预期结果是“QTP 自动化测试技术领航”,即正常的预期结果,输入了什么就显示什么。看一下运行后的测试报告,如图1-249所示。

如图1-249所示,我们可以看到,自动化测试检查已经通过,那么假设现在预期结果不写成“QTP自动化测试技术领航”,看看QTP在自动化测试之后会不会检查出来,代码如下所示:

Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("wd").CheckProperty "value","QTP"

运行后的测试结果如图1-250所示。

图1-249
图1-250

这次可以看到QTP的测试报告Failed掉了,虽然是报错了,但是这也证明了自动化测试的成功,最后再让我们来看看报错的详细情况,如图1-251所示。

图1-251

 

1.10.4 灵活地自定义验证点

上一节是伴随着一张截图结束的,似乎有一些草率。其实,这是有意这样写的,目的是为了引出本小节的内容。在上一节最后的图1-251中可以看到,这些详细介绍情况都是QTP自己生成的,它有自己的一套规则。那么,难道就一直要循规蹈矩地去使用这份默认的报告格式吗?显然不是!QTP提供了一个非常好的测试报告机制,这个机制将是今后最常使用的一个功能,这就是Reporter函数!

首先,Reporter 函数是一个Completed Word,可以快速定位它,如图1-252所示。

在选中函数以后,单击一下“点”,就会出现3个属性和一个方法,如图1-253所示。

图1-252
图1-253

下面主要介绍的是 ReportEvent 方法,本小节的主题也是围绕这个方法展开的。选中这个方法,如图1-254所示。

图1-254

如图1-254所示,在选中了ReportEvent方法以后,QTP自动提示了4个参数,具体怎么用?还是请教一下我们的“兵法书”吧(一定要学会这个方法,作者也绝对不会将兵法书里的内容说成是作者自己原创,它是现成的),双击选中ReportEvent,然后点击F1键,如图1-255所示。

“兵法书”(QTP帮助文档)真的很给力!上半部分是语法介绍,下半部分是示例,已经很简明了。在这里的作用只是通过这个大致框架给广大读者做细分介绍。

首先,一起来看第一个参数EventStatus,在QTP中,一共可以使用4种不同的状态来标识报告的状态,它们分别是。

micPass:对应数字0。

micFail:对应数字1。

micDone:对应数字2。

micWarning:对应数字3。

对应数字的作用就是,既可以直接键入字符,也可以输入字符对应的数字。其实输入字符也很快捷,不用一个一个字母输入,只需很简单地在 ReportEvent 后输入一个空格,QTP就会自动给出这4个事件状态选项,如图1-256所示。

图1-255
图1-256

这里需要注意的地方是,ReportEvent 后面必须跟一个“空格”,不能是其他任何字符或按键,不然会产生语法错误,这也是新手很容易犯的一个错误,而且不容易输入察觉。在选中一个事件状态以后(假设这里选中 micDone ),输入一个“逗号”,就可以开始设置ReportStepName 了,可以根据需要输入任何字符,然后仍然是输入一个“逗号”,开始设置Details,具体内容都由自己决定。最后一个参数是 ImageFilePath,这个参数不是必填项,作用是将截图填入到报告中,当然得把图片相应的路径填对。

这个函数意义大致讲解了一遍,接下来开始进入主题,为什么自定义验证点就比自带的CheckProperty灵活,作者大致总结了一下几点。

(1)CheckProperty使用到的ReportEvent只有两种,Pass和Fail,而后者可以使用4种。

(2)前者似乎永远只是在检查属性,后者可以检查各种各样的代码逻辑,从多角度去验证自动化测试,如For循环,条件判断,嵌套循环等,任意组合都能使用到Reporter函数。

(3)前者的StepName和Details由系统自己生成,显得生硬,后者可以自由键入自己想要的东西。

(4)前者没有将截图写在测试报告里的功能,而后者有。

下面写了一段很简单的代码来抛砖引玉,并在下一小节中一起看看各种报告事件的结果:

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 3,"Step4","3 = micWarning"

Else

End If

Next

 

1.10.5 走进QTP Report——Test Report正式登场

请结合上一小节末尾的代码理解图1-257和图1-258所示。

图1-257
图1-258

先来看第一张图 1-257,我们可以看到,根据代码中的循环顺序,测试报告的状态依次分别是 Passed、Failed、Done 和 Warning,并且请读者记住它们左侧对应的图标,这是有关Reporter函数和测试报告的第一个知识点。

然后再看看,当前的Test最终属于Failed状态,为什么?尽管在4个检查点中,有过Passed (通过)的测试点,但是在 QTP 中,只要整个测试过程中出现了一个测试点 Failed(失败)了,那么它的本次Test迭代就算Failed,哪怕你Passed了99个,但是Failed了一个都不行,这是它们之间的第二个知识点。

再来看看第二张图 1-258,可以看到当前有且只有一次迭代,最终结果 Failed 了。在下方部分则详细地分别显示了Passed、Failed、Warning的测试点次数,但是Done状态的不计算在内,这是第三个相关知识点。

同理,如果两个测试点中有一个Passed,而另一个Warning(警告),Test的最终报告会以Warning显示,先来看下面这个示例脚本:

For i = 1 to 2

If i = 1 Then

Reporter.ReportEvent micPass,"Step1","micPass = 0"

ElseIf i = 2 Then

Reporter.ReportEvent micWarning,"Step2","micWarning = 3"

Else

End If

Next

运行一下QTP,结果如图1-259 中的Test Result。

在最后,再来看看如果两个测试点中有一个 Passed,另一个 Done 的话,Test 的最终报告会以Done显示吗?来看下面这段脚本:

For i = 1 to 2

If i = 1 Then

Reporter.ReportEvent micPass,"Step1","micPass = 0"

ElseIf i = 2 Then

Reporter.ReportEvent micDone,"Step2","micDone = 2"

Else

End If

Next

运行一下QTP,结果如图1-260中的TestResult。

如图1-260所示,可以清楚地看到micDone不会影响 micPass。最后,对它们之间的优先级做总结,从优先级高到低排列:

micFail > micWarning > micPass > micDone

图1-259
图1-260

关于 QTP Report 的一些功能点,读者可以亲自使用一番,有的功能点还是比较实用的,比如右键单击一些步骤,可以直接跳转到QTP的脚本中、和QC的交互操作等……更多亮点期待读者去挖掘、尝试、探索!

 

1.10.6 自定义验证点——HTML模式

这一小节是扩展知识,讲的是自定义过程校验,内容比较特别,正常情况通过前面小节的学习都已经知道了:自定义报告可以直接使用 Report 对象,或者直接使用验证点函数CheckProperty,然后让 QTP 去自动在 Report 里生成一条验证结果。以上的就不多说了,相信读者已经掌握。这里主要是讲一下怎么结合验证点在QTP Report中输出HTML格式的结果,看下面这个例子,如图1-261所示。

图1-261

图1-261就是我们需要实现的最终结果,来看一下脚本的实现。

1.报告生成函数(过度函数)

注意:这里的GetTOProperty ("testObjName")是一个隐藏属性,可以获取QTP 对象库里的对象的LogicName:

'######################### 报告生成 ###########################

private Function HReport(ExpectedValue,ActualValue,testStatus,nodename)

Set oEventDesc = CreateObject("Scripting.Dictionary")

'添加状态

oEventDesc("Status") = micFail

'添加是否过滤

oEventDesc("EnableFilter") = False

'添加节点名称

oEventDesc("NodeName") = nodename

'添加HTML结果

oEventDesc("StepHtmlInfo") = "<TABLE border='1'>" & _

"<TR><TD>Actual Value</TD><TD>"+ExpectedValue+"</TD></TR>" & _

"<TR><TD>Expected Value</TD><TD>"+ActualValue+"</TD></TR>" & _

"<TR><TD>Checkpoint Status</TD><TD style='background-color:red'><b>Failed</b></TD></TR>" & _

"</TABLE>"

'判断状态

If testStatus Then

oEventDesc("Status") = micPass

oEventDesc("StepHtmlInfo") = Replace(oEventDesc("StepHtmlInfo"),_

"<TDstyle='background-color:red'><b>Failed</b></TD>","<TDstyle='background-color:green'><b>Passed</b></TD>")

End If

'生成报告

newEventContext = Reporter.LogEvent ("Replay",oEventDesc,Reporter.GetContext)

'释放资源

Set oEventDesc = nothing

End Function

2.验证函数-调用第一个报告生成函数自动判断成功与失败:

'########################### 自定义过程校验 ##########################

Function ValidateProperty (Object, PropertyName, ExpectedValue)

'判断预期是否与实际值相等

If Object.GetROProperty (PropertyName) = ExpectedValue Then

'成功

HReport ExpectedValue,Object.GetROProperty(PropertyName),true,_

"check "+Object.GetTOProperty("testObjName")+"<"+PropertyName+">属性"

ValidateProperty = True

Exit Function

Else

' 失败

HReport ExpectedValue,Object.GetROProperty(PropertyName),false,_

"check "+Object.GetTOProperty("testObjName")+"<"+PropertyName+">属性"

ValidateProperty = False

Exit Function

End If

End Function

这里的验证函数使用了测试对象的抽离技术。调用时可以直接把对象传入。把以上两个函数都存放在函数库中,然后直接调用验证函数(ValidateProperty)即可:

Set oWebEdit = Browser("百度一下,你就知道").Page("百度一下,你就知道")._

WebEdit("搜索框")

VaildateProperty oWebEdit,”name”,”wd”

ValidateProperty oWebEdit,"name","wd1"

结果1:wd验证成功,如图1-262所示。

图1-262

结果2:wd1验证失败,如图1-263所示。

图1-263

 

1.10.7 总结

验证点和测试报告作为自动化测试脚本的最后一关是非常关键的。验证点随着业务逻辑的复杂度而千变万化。验证点的质量直接反应自动化测试的可靠性;测试报告是一门技术活,测试报告写的好,能一目了然地反应程序或者代码本身的问题。在本章中,凡是关于这类的内容上,不过这些都将在第二大章中逐步展现。

同时,随着验证点和测试报告的学习完毕,也就意味着读者已经掌握了所有基本理论操作知识和实战技巧,接下来的积累已经不再是“学习”这个层面上了,应该是积累和扩展!

 

知识点巩固和举一反三练习

一、使用自身接口的方式验证“百度一下”这个按钮的界面是否符合需求。

二、学会将关键信息输入至Test Result中。

相关图书

现代软件测试技术之美
现代软件测试技术之美
渗透测试技术
渗透测试技术
JUnit实战(第3版)
JUnit实战(第3版)
深入理解软件性能——一种动态视角
深入理解软件性能——一种动态视角
云原生测试实战
云原生测试实战
Android自动化测试实战:Python+Appium +unittest
Android自动化测试实战:Python+Appium +unittest

相关文章

相关课程