QTP-测试自动化框架的设计与实现-全-
QTP 测试自动化框架的设计与实现(全)
原文:
zh.annas-archive.org/md5/1cf42fa1f1def13c87def05afdd90d57译者:飞龙
前言
HP QuickTest Professional 是用于软件应用程序和环境的功能性和回归测试的自动化测试工具。HP QuickTest Professional 支持关键字和脚本接口,并具有图形用户界面。它使用 Visual Basic Scripting Edition (VBScript)来指定测试过程,并操作正在测试的应用程序的对象和控制。
本书是一个很好的平台,用于分享我在信息技术领域工作并教授专业人士 QTP 多年以来所获得的设计和实施测试自动化框架的知识。如果任何专业人士或学生发现实施框架有困难,这本书就是正确的选择——它通过简单的示例教授方法和概念。本书涵盖了管理、技术和设计概念,独特地设计用于提供创建有效框架所需的知识。它展示了实现和学习的简单方法,包括代码和建议,用于在 QTP 的各个版本之间创建可移植的框架。
本书还涵盖了使用 XPath 在 QTP 中创建测试自动化以及使用 JavaScript 为自动化 Web 应用程序创建的新特性。
本书涵盖的内容
第一章, 自动化生命周期和自动化目标,解释了自动化生命周期和工具选择,这些有助于实现更好的测试自动化流程和工具选择。本章还解释了整体自动化和设计目标,这些目标有助于开发更好的测试自动化框架,并指导您实施更好的实践以实现最大输出。
第二章, 自动化的要素,解释了使用 QTP 进行测试自动化设计的关键元素,以及如何使用每个元素的示例。这些元素是创建完整测试自动化脚本的基石。
第三章, 创建框架的基本构建块,解释了设计测试自动化框架实现的基本代码构建块(包括示例),所有这些都在实现框架(s)时使用。
第四章, 理解和创建框架,解释了我们所说的测试自动化框架是什么,以及存在哪些类型的框架。它指导您在我们设计和实现它们之前理解这些框架。本章还将突出它们之间的差异和共性。
它解释了测试自动化框架的基础知识,并构建了用户在端到端实施测试自动化框架方面的成熟度。
第五章, 部署和维护框架 在设计阶段的开始解释了如何以及需要做什么来轻松维护和增强这些框架。
第六章, 基于 DOM 和 XPath 的 Web 应用程序框架 解释了各种基于 Web 的技术,并构建了实施这些技术的成熟度,以用于自动化的 Web 应用程序。它解释了 HTML、XPath、DOM、JavaScript 以及如何有效地使用它们来创建测试自动化脚本。
第七章, 捕捉经验教训 解释了为了学习应该捕捉什么,以及如何确保这些经验教训有助于未来的项目或作为其他项目的输入。
你需要这本书的以下内容
我们需要以下软件才能开始使用本书:
-
QTP 11.0
-
Windows XP 或 Windows 7 32 位系统,配备 IE 8
-
IE 9 的 QTPWEB_00078 补丁
-
Windows 7 64 位系统补丁 QTP_00699
-
QTPWEB_00086 补丁支持 64 位 IE
注意
在安装此补丁之前,请先安装 QTP_00699 补丁。
本书面向对象
本书对手动测试人员、测试负责人、测试架构师、自动化工程师以及想要学习、创建和维护框架的渴望成为自动化测试工程师的人来说很有用。它使他们能够加速测试自动化框架的开发和适应。本书将为测试人员提供使用 QTP 创建框架的技术和概念知识。
本书对从手动测试转向测试自动化和 QTP 的人来说也很有用。
习惯用法
文本中的代码词、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL 和用户输入如下所示:“<html> 标签是根节点,它没有父节点。”
代码块设置如下:
Window("WinFlight").WinButton("Insert Order").Click
'Window("WinFlight").WinButton("Button").Click
'When QTP tries to execute the below statement, application will not allows to click on the button, since it is waiting to reach progress bar to 100% and display the message Insert Done..
' Here script will fail
' We need to insert the dynamic synchronization point and this waits until the text does not changes to Insert Done…
'Window("WinFlight").ActiveX("ThreedPanelControl").WaitProperty "text", "Insert Done...", 10000
新术语和重要词汇以粗体显示。屏幕上显示的词,例如在菜单或对话框中,文本中显示如下:“点击下一步按钮将您带到下一屏幕。”
注意
警告或重要注意事项以如下框中所示。
小贴士
小贴士和技巧看起来像这样。
读者反馈
我们欢迎读者的反馈。告诉我们您对这本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们来说很重要,以便我们开发出您真正从中受益的标题。
要向我们发送一般反馈,只需发送电子邮件到 <feedback@packtpub.com>,并在邮件主题中提及书籍标题。
如果你在某个领域有专业知识,并且你对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南 www.packtpub.com/authors。
客户支持
现在你已经是 Packt 书籍的骄傲拥有者,我们有许多事情可以帮助你从购买中获得最大收益。
下载示例代码
你可以从你购买的所有 Packt 书籍的账户中下载示例代码文件。www.packtpub.com。如果你在其他地方购买了这本书,你可以访问 www.packtpub.com/support 并注册,以便将文件直接通过电子邮件发送给你。
错误
尽管我们已经尽一切努力确保我们内容的准确性,但错误仍然会发生。如果你在我们的一本书中找到错误——可能是文本或代码中的错误——如果你能向我们报告这一点,我们将不胜感激。通过这样做,你可以帮助其他读者避免挫败感,并帮助我们改进这本书的后续版本。如果你发现任何错误,请通过访问 www.packtpub.com/support,选择你的书籍,点击错误提交表单链接,并输入你的错误详情来报告它们。一旦你的错误得到验证,你的提交将被接受,错误将被上传到我们的网站,或添加到该标题的错误部分现有的错误列表中。
盗版
在互联网上对版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果你在互联网上发现我们作品的任何非法副本,无论形式如何,请立即提供位置地址或网站名称,以便我们可以追究补救措施。
请通过 <copyright@packtpub.com> 联系我们,并提供涉嫌盗版材料的链接。
我们感谢你在保护我们作者和我们提供有价值内容的能力方面给予的帮助。
问题
如果你在这本书的任何方面遇到问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决。
第一章. 自动化生命周期和自动化目标
测试自动化工具创建一系列脚本,模拟要在被测应用(AUT)上执行的用户操作,并反复播放,以最小或没有人为干预。测试自动化是一个完整的过程,它通过不同的阶段来自动化测试用例。AUT 可以属于任何技术或领域。
测试自动化应尽早开始于项目的生命周期中,其成功取决于以下因素:
-
自动化生命周期知识
-
测试自动化的流程
-
选择正确的工具
-
测试自动化规划
-
适当的自动化和测试自动化工具的技术知识
成功测试自动化的关键驱动和指导力量是自动化目标、最佳实践、选择标准以及工具选择和流程的属性。
在这些领域有良好的知识有助于有效地实施测试自动化。
测试自动化生命周期
测试自动化生命周期是测试自动化通过一系列不同阶段进展的过程。本章的重点是学习在生命周期的每个阶段执行的关键活动和任务。
可行性研究
可行性研究是对潜在工具的评估和分析,可以为项目(s)的测试自动化需求提供所需的解决方案。目的是客观和理性地揭示工具(s)的优缺点。通常,它先于测试自动化实施。
手动和自动化工作所需进行的可行性研究应基于以下方面:
-
投资回报率(ROI)
-
未来改进
在测试自动化规划中,应考虑测试用例、自动化工具、自动化环境、自动化测试的开发和维护、技能集、组织能力、设计以及自动化方法。
定义 ROI 最简单的方式是 ROI = 收益/成本。
在计算了投资回报率(ROI)之后,可以做出是否继续的决定。应用/服务未来的变化可能既带来许多威胁,也带来测试自动化的机会。领导和经理需要有清晰的视野来评估未来改进的 ROI。
测试经理或领导应专注于最大化测试自动化的 ROI。他/她应专注于降低维护成本和实现测试套件的快速可扩展性。计算 ROI 是一项重要活动,它使我们能够预见许多权衡,并指导测试自动化的实施。由于计算 ROI 超出了本书的范围,所以我们只能做到这一步。
自动化测试的工具引入
此阶段旨在成功引入工具并建立所需的基本基础设施,或识别测试引入的需求。
测试引入的关键步骤如下列出:
-
确定技术/非技术需求:
-
技术需求例如对技术、工具和脚本语言的支撑
-
非技术需求例如测试自动化的目标
-
-
根据所选属性及其相应权重评估工具。当对工具(们)了解有限时,工具评估是技术挑战性最大的任务之一。
-
如用户友好性、许可成本和培训成本等属性定义了工具功能
-
在工具选择过程中,赋予最相关属性更高的权重(高数值)
通过计算权重和价值的乘积之和来计算总体分数,即 总分 = ∑ 属性权重 * 属性值。值的范围可能不同,例如从零到五。
- 最终选择基于工具(们)计算出的最终分数
-
-
验证运行是在创建样本脚本以验证所选工具是否在所选测试用例上按预期工作。如果验证运行成功,您可以购买许可证或获取工具。
定义测试自动化策略
测试自动化策略是为实现测试自动化总体目标而设计的行动计划。它提供广泛的指导,以便利益相关者了解测试自动化的设计和实施方法。少数组织将测试策略和测试计划合并为单一文档。
测试策略定义以下内容:
-
范围
-
框架和设计方法
-
脚本创建方法
-
需要的测试量
-
风险和缓解计划
-
可交付成果
创建自动化测试计划
规划是思考并展望测试自动化所需活动和任务的过程。测试计划定义以下内容:
-
测试架构
-
工具安装计划
-
测试时间表
-
角色和职责
-
资源需求(硬件、软件和熟练资源)
-
培训需求
-
审查脚本和设计文档的计划
-
局限性和假设
测试计划文档告诉我们测试自动化要做什么,何时做。此文档由所有利益相关者使用,并在关键利益相关者之间作为合同协议。
脚本设计和开发
这是关键阶段,实际工作在此阶段实施。此阶段需要设计框架的技术技能,以及与 SMEs(领域专家)、BAs(业务分析师)、手动测试人员和开发人员互动的协调技能,以完成测试自动化的各种任务。负责人必须确保已进行审查并遵循编码标准;然后创建测试库结构,并将所有资源保存在适当的位置。我们将在以后创建理解、使用和增强测试自动化的文档。
设计和开发阶段的关键步骤如下:
-
分析和脚本规划
-
脚本创建(脚本可以通过录制或手动创建)
-
创建通用和框架特定的库
-
脚本增强(添加异常处理程序、检查点等)
-
将库和函数与脚本关联或集成
-
审查(确保遵循计划或策略文档中已定义的一致性、编码标准和版本控制)
-
预演和分析结果
-
调试脚本并修复缺陷
部署、发布和维护
在前一阶段我们已经进行了预演;现在,我们需要将脚本部署到具有良好结构和数据的适当位置。实际的执行可能不是由开发测试脚本的那些人进行的,因为它可能由业务用户、SMEs 或其他自动化工程师执行;因此,在发布测试脚本之前,应确保所有必要的文档和自动化资源都已到位并经负责人或团队成员审查。
部署、发布和维护阶段的关键步骤如下:
-
部署:在测试自动化脚本部署后,自动化工程师、SMEs 或甚至业务用户都可以使用它们
-
发布:在这个阶段,以下工件将被交付(列表可能根据项目的需求而变化)
-
框架组件/脚本
-
库、函数和数据池
-
发布说明
-
映射文档(可追溯性矩阵)
-
设计/架构文档
-
-
维护:在这个阶段,我们将执行以下操作:
-
在这里,我们分析由于脚本或应用程序问题、日志导致的失败,并修复它们
-
根据每个周期/发布的需要增强脚本
-
执行每个周期的脚本
-
在一段时间内,GUI 中的对象和 AUT 的流程会发生变化;因此,需要更改对象库(OR)中的测试对象和脚本。
工具选择
我们现在需要确定关键需求,这些需求应涵盖组织级和项目级所需技术的深度和广度。
捕获自动化需求
测试自动化的需求来自以下方面:
-
测试自动化的组织级要求
-
组织中使用的科技
-
工具如何支持这些技术的自动化
-
项目级或特定项目的要求
-
关键技术领域
开发 POC
进行概念验证(POC)的关键步骤如下:
-
确定 POC 的最小测试集
-
验证技术可行性
-
如果我们轻松实现工具的实施,验证实施可行性
-
查找是否存在任何已知的限制
-
提交 POC 总结报告
评估工具
评估工具的关键步骤如下:
-
确定最适合您项目的关键属性:例如,技术支持、技术版本等
-
给属性赋予适当的权重和价值;总分是权重和价值的乘积之和,如下所示:
总分 = ∑ 属性权重 * 属性值
-
工具的最终选择基于总分
工具选择标准
以下是在考虑工具选择时应考虑的属性的综合但非完整列表:
-
可靠性:这是工具在常规情况下以及敌对或意外情况下执行和维护其功能的能力。
-
容量:这指的是系统的可能输出,即在高效和有效的方式下创建和执行脚本。
-
易学性:这个工具学习起来既快又简单。
-
可操作性:这是在各种配置和环境下的工作能力。
-
性能:给定任务的完成情况与目前所知的准确性、完整性、吞吐量和速度标准进行比较。
-
兼容性:这检查工具是否支持技术的各种版本、浏览器或操作系统。
-
非侵入性:在选择工具时应考虑的关键非侵入性特性如下:
-
平台/操作系统无关
-
数据驱动能力
-
可定制的报告
-
邮件通知
-
容易调试和日志记录
-
支持版本控制
-
可扩展和可定制(开放 API 应该能够与其他工具集成)
-
常见日志记录驱动器
-
支持分布式执行环境
-
分布式应用程序支持
-
许可和支持(成本)
-
从更广泛的角度来看,测试自动化是由以下因素驱动的:
-
组织内部定义的过程
-
设计和架构
-
自动化目标
-
测试自动化的最佳实践
所有这些特性相互补充,以确保测试自动化的成功。
流程
一个过程可以被描述为执行自动化生命周期中发生的各种任务和活动的结构化方法。由有能力的组织制定的明确过程为从构思到完成提供指导。
在没有良好制定的过程和历史数据的情况下,很难估计、计划和实施测试自动化。如果一个组织是第一次实施测试自动化,它将成为未来测试自动化的学习曲线,并为未来的项目提供历史数据。
设计、架构和文档
明确的架构/设计有助于减少开销和冲突;它还有助于团队更好地协作和实现更好的实施。设计解决方案的关键方面是提供从复杂性、封装和技术挑战中抽象出来的能力。我们需要开发支持库,以提高自动化解决方案的可重用性和可扩展性。
我们必须记录设计和架构。脚本中的注释、脚本标题和函数标题提高了可读性和可理解性。文档有助于快速轻松地增强和维护脚本。
自动化目标
目标是人们所设想的结果。它是实现某种假设开发中期望的终点的计划和承诺。目标是测试自动化成功的关键驱动和指导力量。设计需要将框架解决方案分解成组件和层。自动化目标应在每个级别或层上实现,以确保测试自动化的整体成功。
备注
定义目标的目标是明确结果。目标在每一层定义,并且对彼此有级联效应。它们还推动并贡献于彼此的成功。
测试自动化的目标
整体自动化设计目标是根据组织目标、领域、业务等得出的。此列表可能因组织而异。以下是一些例子:
-
提高可重用性
-
增强测试覆盖率
-
加快多次和频繁发布的测试
-
确保一致性
-
提高测试的可靠性
-
可扩展性
框架设计的目标
以下是基于组织、领域等设计的框架设计目标列表。此列表可能有所不同。
-
可维护性
-
可读性
-
可扩展性
-
可重用性
-
与应用程序无关
-
应该有简短的驱动脚本/主脚本
设计的目标
以下是基于组织、领域等设计的测试自动化解决方案或框架的目标设计组件列表:
-
设计应该是易于扩展和维护的
-
它应该提供从复杂性中抽象出来的功能
-
识别跨脚本使用的公共函数
-
将复杂业务功能与实用函数解耦
-
解耦测试数据和测试脚本
-
创建健壮的函数
-
适当的函数分解,具有可移植性
-
确保脚本在没有人为干预的情况下执行,即使在错误条件下也是如此
-
设计文档
脚本设计的目标
以下测试自动化脚本/代码的目标列表基于组织、领域等。此列表可能有所不同。
-
测试应该始终有一个共同的起点和终点
-
应清理可重用的资源,例如,删除旧的日志文件、结果文件等
-
如果发生错误,测试应该揭示最大信息
-
配置值而不是硬编码
-
应该有适当的注释和脚本标题
-
代码应该是可读的,并且应该有适当的文档
-
脚本应该是可维护的和易于修改的
-
应该有错误处理和错误快照
-
应提供日志工具
设置可衡量的目标
为测试自动化项目设定明确、可衡量的目标是至关重要的。这些目标应该明确地提出。以下是一些例子:
-
要自动化的测试用例的数量或百分比
-
通过百分比或数字提高测试覆盖率
-
通过百分比或数字减少构建发布时间
-
减少新版本测试周期时间
没有设定可衡量的目标,很难获得期望的结果或甚至 ROI;这将导致高昂的维护成本,对脚本的更改将产生副作用。
最佳实践
测试自动化是任何软件开发和维护项目的重要组成部分。以下的一些最佳实践将使测试自动化项目取得成功。
选择最适合自动化的工具
一个不适合的自动化测试工具会增加设计、创建脚本和维护它们的工作量,从而增加自动化测试的成本,甚至可能无法实现自动化目标。选择合适的工具是赢得一半战斗的关键。合适的工具有助于加快脚本创建、修改,识别脚本中的问题,并快速解决它们;简而言之,它使测试自动化团队的工作变得更加容易。
将测试自动化视为一项开发活动
将测试自动化与开发项目相同的纪律和客观性对待。一个成功的测试自动化项目采用框架驱动的方法。根据 AUT 功能分解脚本,并将它们划分为可重用的函数。创建一个定义良好的结构,允许资源均匀共享。准备适当的文档:增强可读性和可维护性的文档。确保遵循了脚本/编码标准。最后,您需要测试和调试脚本或代码,并确保脚本没有错误。检查脚本和资源是否使用版本控制工具或机制也是好的。
获得正确的架构
如果不使用框架驱动的方法,扩展和维护自动化测试将变得困难。整体设计变得混乱或难以修改或增强。测试自动化框架允许我们定义自动化测试的脚本方法,创建支持库和公共资源以执行测试,并报告结果。框架允许以最小的努力添加测试用例。它还允许建立共同的标准和一致的方法来实现自动化团队的目标。
确保相关且最新的测试数据
如果数据过时且不相关,测试自动化套件可能无法捕捉到错误。近生产数据(与生产数据最相似的数据)确保测试数据映射到 GUI 中的正确字段。它不应包含前导和尾随空格。使用拼写正确的测试数据,因为它可能与从下拉菜单中选择值相关,例如,在多个测试中明智地选择用于重用的数据。测试数据有助于提高代码覆盖率。经过一段时间后,测试数据可能变得不相关;因此,应将其替换为相关且最新的测试数据,以便快速轻松地发现错误。
投资于团队建设和培训
除了正确的工具和良好的流程之外,测试自动化项目还需要一个专门的和有技能的团队来理解项目的复杂性并将其转化为脚本。技能组合中的差距会导致工作交付不平衡,导致工作质量低下和团队成员士气低落。负责人或经理应确保团队获得足够的培训,以弥补(如果有的话)技能组合中的差距。
进行审查和测试
没有正式的审查,很可能会发现缺陷,并且不会遵循标准,导致框架组件集成的潜在问题。这会导致额外的成本和努力。审查有助于主动发现早期问题和潜在风险,并迅速缓解它们。审查还确保项目的一致性,并控制问题。
摘要
自动化生命周期是一种设计、执行和维护测试自动化的结构化方法。这种结构化方法对于帮助测试团队避免常见的测试程序/自动化错误是必要的。
本章从更广泛的角度涵盖了测试自动化的各个方面。了解自动化生命周期以及每个阶段的关键活动有助于简化任务和目标。明确的过程和历史数据有助于测试估算、工具评估和选择。架构或设计基于实施测试自动化和实现目标。在下一章中,我们将讨论 QTP 的各种特性和创建可重用脚本所必需的概念。
第二章. 自动化的基本要素
在第一章中,自动化生命周期和自动化目标,我们学习了测试自动化生命周期和自动化目标。测试自动化的基本功能是录制和回放。这些功能允许用户多次播放脚本,并将预期值与实际值进行比较。这种方法简单,且对编码知识的要求很少或没有,可以应用于任何具有图形用户界面的支持应用程序。应该熟悉基本 QTP 功能,如录制、回放、对象库(OR)创建、检查点、同步、动作、报告、错误处理、参数化和配置。还应该了解如何使用环境变量使脚本完整且可重用。本章旨在处理录制或创建测试脚本、脚本创建生命周期、QTP 功能和各种使用这些功能创建完整可重用脚本的方法。本章的目的是熟悉这些功能,以便于脚本创建和增强。
关于 QTP
HP QuickTest Professional (QTP或 QuickTest)或Unified Functional Tester (UFT)是用于功能性和回归测试用例自动化的测试自动化工具。HP QuickTest Professional 支持关键字视图和脚本接口来自动化测试。它使用 VBScript 作为脚本语言来指定测试脚本,并与测试中的应用程序中的对象和控件一起工作。
QTP 是一个提供自动化软件测试和框架创建支持的工具。支持 QTP 录制和回放机制的基本组件包括测试对象模型、测试对象和对象库。对这些组件的了解和理解有助于创建脚本。
QuickTest 对象模型
测试对象模型是一组对象和类,它表示 AUT 中的对象。每个类都有一组属性用于其标识;QTP 使用属性的一个子集在运行时唯一地识别对象。
测试脚本是由标准 VBScript 语句和用于 QuickTest 测试对象、方法和属性的语句组合而成的。QuickTest 对象模型包含一个部分,用于表示 QTP 安装中可用的每个插件环境,以及一个用于实用程序和补充对象的特殊部分。
测试对象
QTP 使用测试对象来表示 AUT 中的对象。每个测试对象都有一组方法和属性,用于执行操作和检索该对象的价值。每个测试对象都有一些标识属性,用于描述该对象。
对象识别属性可以用在对象存储库描述、程序性描述、检查点、输出值、测试步骤中,并作为 GetTOProperty 和 GetROProperty 方法的参数值传递。运行时对象是在运行会话期间在 AUT 上执行方法的实际对象。
对象存储库
在创建测试之前设置资源。任何测试最重要的资源之一是对象存储库,它存储了测试中使用的测试对象(以及其他对象类型)。QuickTest 可以在两种类型的对象存储库文件中存储它所学习的测试对象:共享和本地。
一个共享对象存储库包含可以在多个操作中使用的测试对象。
一个本地对象存储库存储只能用于特定操作的测试对象,不能用于其他操作。
记录和回放
记录是一个捕捉在 AUT 上执行的人类动作的过程,并同时创建一个可以在 AUT 上多次回放的脚本。
记录时会发生什么
当用户记录脚本时,QTP 会执行以下步骤中的各种任务:
-
QTP 使用测试对象模型。它识别属于 AUT 的测试对象和对象上执行的操作。
-
然后将测试对象存储在用户执行操作的本地对象存储库中。
-
捕获测试对象的对象识别属性,这允许在回放时唯一地识别该对象。
-
它为测试对象提供了一个逻辑名称,这使得对象的名称易于阅读。
-
创建测试步骤;测试步骤包含测试对象,包括父对象、操作和(如果适用)数据。以下代码是测试步骤的示例:
Dialog("Login").WinEdit("Agent Name:").Set "ashish"
在上一个测试步骤中,Dialog 是类名,Login 是其逻辑名称,它是 WinEdit 对象的父对象。WinEdit 是类,Set 是操作,它将值设置为 ashish 到逻辑名称为 Agent Name 的对象:
记录的步骤如下:
-
点击工具栏上的记录按钮,如图所示:
![记录时会发生什么]()
-
在 AUT 上执行操作。
-
重复步骤 2 以记录其他测试步骤。
回放时会发生什么
当 QTP 回放脚本时,它执行以下步骤中的各种任务:
-
QTP 找到测试对象。
-
它唯一地识别测试对象;在某些情况下,它可能使用以下一项或多项:序号标识符、智能识别和关系标识符。
-
在运行时对象上执行预期操作。
记录的步骤如下:
点击工具栏上的运行按钮,如图所示:

脚本开发
脚本开发的步骤如下:
-
分析待测试的应用程序。
-
创建 OR(手动添加测试对象)。
-
添加测试步骤。
-
通过添加检查点、同步点等增强脚本。
-
通过插入函数、操作、循环和控制语句创建结构。
-
运行和调试测试。
-
分析结果并报告缺陷。
-
从 OR 拖放对象到专家视图。
我们将在后续章节中讨论前述步骤 4、5 和 6。
分析应用程序
确定开发环境以加载相关的 QuickTest 插件并提供对 AUT 中对象的支持。分析流程并相应地规划测试和操作。决定测试的组织结构,并确保测试和 AUT 设置为满足自动化的需求。
创建 OR(向 OR 添加测试对象)
当对象被添加到对象库时,QuickTest 执行以下操作:
-
它识别测试对象类,该类代表学习到的对象并创建适当的测试对象。
-
它读取对象在 AUT 中的当前属性值以及存储识别属性列表。它选择可以唯一识别测试对象的识别属性。
-
它为测试对象选择一个唯一名称,通常使用其突出属性之一的价值:例如,如果对象有一个,则使用
name。
以下是向 OR 添加测试对象的方法:
-
记录测试步骤。
-
将对象添加到本地。
-
创建对象描述。
-
通过使用定义新测试对象创建测试对象。
-
OR 管理器导航和学习或添加对象选项。
-
从Active Screen将测试对象添加到本地对象库。
记录测试步骤
当用户记录一个步骤时,测试对象会自动创建并添加到本地 OR 中。将对象添加到本地。
将测试对象添加到 OR
通过以下步骤将测试对象添加到本地 OR:
-
导航到资源 | 对象库 | 添加对象到本地。
-
点击添加对象到本地按钮。
-
点击我们想要从 AUT 中添加的对象的手指针。
-
点击确定。对象已添加到 OR 中,如下截图所示:
![将测试对象添加到 OR]()
创建对象描述
测试对象可以通过提供对象描述来创建,而无需记录。请参考以下截图。测试对象类名为WinComboBox,它有两个描述属性,这些属性以逻辑名称Fly From存储:

当我们记录测试步骤以从Fly From组合框中选择一个选项时,将生成以下脚本:
Window("FlghtReservation").WinComboBox("Fly From:").Select "London"
我们可以直接在测试步骤中使用对象描述,如下所示:
Window("regexpwndtitle:=FlghtReservation").WinComboBox("attached text:=Fly From:").Select "London"
当我们回放脚本时,这两个语句是相同的,一个使用 OR 中的对象,另一个直接使用描述。当我们使用程序性描述时,逻辑名称被替换为识别属性及其值的对。
使用“定义新测试对象”创建测试对象
要定义一个新对象,我们应该知道它的类及其标识属性。执行以下步骤:
-
导航到资源 | 对象库 | 定义新测试对象。
-
从定义新测试对象窗口中筛选环境。
-
从类下拉框中选择班级。
-
输入一个逻辑名称。
-
提供标识属性的值(1 到 n)。
-
如有需要,添加一些标识属性。
-
点击添加按钮将测试对象添加到 OR 中:
![使用“定义新测试对象”创建测试对象]()
根据加载的插件选择显示的环境,选择类,并提供一个逻辑名称。
OR 管理器导航和学习以及添加对象选项
-
如何一次性学习 GUI 对象?
-
在 OR 管理器中使用导航和学习功能。
导航和学习工具栏
此工具栏允许您在导航应用程序时将多个测试对象添加到共享对象库中。以下是在对象库管理器中学习导航对象的步骤:
-
导航到资源 | 对象库管理器 | 对象 | 导航和学习或按F6。
![导航和学习工具栏]()
-
选择一个窗口进行学习。根据预定义的对象筛选器,选定的窗口及其后代对象被添加到活动共享对象库中。
使用 OR 管理器的“添加对象”选项添加测试对象
-
导航到资源 | 对象库管理器 | 对象 | 添加对象。点击手指指针并选择窗口。
-
对象筛选器用于导航和学习选项以及添加对象选项。
![使用 OR 管理器添加对象选项添加测试对象]()
以下表格中说明了每个筛选器的描述:
| UI 元素 | 描述 |
|---|---|
| 仅选定的对象(无后代 ) | 此选项允许您选择没有后代的对象,并通过先前选择及其属性添加选定的对象。 |
| 默认对象类型 | 此选项允许将选定的对象及其后代添加到对象库中。选定的对象由默认过滤器选项指定。 |
| 所有对象类型 | 此选项允许使用选定的对象类型选项在对象库中使用先前选择的具有属性和值的对象及其后代添加。 |
| 选定的对象类型 | 此选项允许选择和筛选对象及其后代。选择在用户不更改选择标准之前保持有效。 |
根据筛选器选项,其他对象被添加到 OR 中。
从活动屏幕向本地对象库添加测试对象
从活动屏幕中选择所需的对象并将其添加到对象库中。为了使用活动屏幕将测试对象添加到对象库中,活动屏幕应该有该对象。执行以下步骤:
-
转到活动屏幕面板。
-
选择一个对象并右键单击。
-
点击视图/添加对象。
-
点击添加到库按钮。
![从活动屏幕添加测试对象到本地对象库]()
我们已选择如前图所示的“取消”对象按钮。测试对象已添加到本地对象库中,并且只能由当前动作使用。我们无法使用活动屏幕在共享对象库(在对象库管理器中)中添加测试对象。
添加测试步骤
我们可以在脚本中添加步骤的许多方法,如下所示:
- 录制:当用户在 AUT 中执行对象操作时,录制会创建测试步骤。
手动添加步骤:要手动添加步骤,我们需要首先添加对象库。写下类名,例如Dialog;编辑器显示对话框列表。如果对象库中存储了多个对话框,我们可以选择所需的对话框。如果只有一个对话框,QTP 将完整打印其名称在编辑器中。当用户输入WinEdit时,编辑器显示属于WinEdit类的两个对象。参见图示:


在WinButton("OK")后按.键,将出现包含对象可用方法的下拉菜单。选择适当的方法并完成语句。
执行以下步骤以进行关键字视图:
-
创建对象库。
-
切换到关键字驱动视图。
-
右键单击项目列。
-
从网格项的下拉菜单中选择对象。
-
从操作列中选择方法。
-
如有必要,在值列中设置值。
注意
注释将由 QTP 自动添加。
如果在插入步骤之前未将测试对象添加到对象库中,请从项目列的下拉菜单中点击对象库中的对象。点击手形指针以从所选测试对象窗口中添加对象库中的测试对象。

关键字视图中的步骤生成器:
-
创建对象库(将对象添加到对象库)。
-
切换到关键字驱动视图,并右键单击。
-
点击步骤生成器。
-
从类别中选择测试对象。
-
从下拉菜单中选择测试对象或点击图标(选择测试对象)以打开所选对象窗口。
-
选择测试对象。
-
提供参数并点击确定。
向活动屏幕添加步骤:
-
打开活动屏幕面板(如果活动屏幕面板不可见,请转到视图 | 活动)。
-
导航到我们想要添加的对象。
-
点击步骤生成器选项。
-
从类别中选择测试对象。
-
从下拉菜单中选择测试对象或单击图标(选择测试对象)以打开选定的对象窗口。
-
选择测试对象。
-
提供参数。
增强脚本
我们已经学习了添加测试对象和创建测试步骤的各种方法,现在我们将学习如何使用检查点、动作、同步点、报告对象、错误处理和环境变量来增强脚本,使其更具可重用性和有效性。
检查点
检查点是一种验证,它将对象的指定属性的实际值或其他特性的当前状态与预期值或特性进行比较。这允许通知运行结果窗口或脚本,以确定应用程序是否按预期工作。当检查点添加到测试中时,QuickTest 在关键字视图中插入一个检查点步骤,并在专家视图中添加一个CheckPoint语句。当执行测试时,QuickTest 使用检查点比较预期结果和实际结果。如果存在不匹配,则检查点失败。检查点的结果可以在运行结果查看器中查看。以下列表显示了各种检查点的类型:
| 类型 | 描述 | 如何插入 | 使用示例 |
|---|---|---|---|
| 标准检查点 | 验证对象属性值 | 在工具栏中单击记录。转到插入 | 检查点 | 标准检查点。 | 验证对象的属性 |
| 图片检查点 | 验证图片的特性 | 通过选择标准检查点选项,然后选择检查网页图片对象来插入此检查点类型。 | 验证图片的alt属性 |
| 表格检查点 | 验证网页表格中的信息 | 通过选择标准检查点选项,然后选择检查任何表格对象来插入此检查点类型。 | 验证网页表格中单元格的值是否正确 |
| 页面检查点 | 验证网页的特性 | 通过选择标准检查点选项,然后选择检查网页对象来插入此检查点类型。 | 验证链接数量 |
| 文本检查点 | 验证显示的文本或预定义和后定义值内的文本 | 在工具栏中单击记录。转到插入 | 检查点 | 文本检查点。 | 验证是否显示了预期的文本字符串 |
| 文本区域检查点 | 验证是否在定义的区域内显示了字符串 | 在工具栏中单击记录。转到插入 | 检查点 | 文本区域检查点。 | 验证定义区域中的字符串是否与预期字符串匹配 |
| 位图检查点 | 验证位图或位图的一部分 | 在工具栏中点击记录。导航到插入 | 检查点 | 位图检查点。 | 检查位图是否与预期的位图匹配 |
| 数据库检查点 | 检查查询检索的值是否与预期值匹配 | 导航到插入 | 检查点 | 数据库检查点。 | 检查查询检索的值是否与预期值匹配 |
| 可访问性检查点 | 识别网站需要检查的 508 合规性区域 | 在工具栏中点击记录。导航到插入 | 检查点 | 可访问性检查点。 | 检查网页上的图像是否包含 W3C Web 所需的ALT属性 |
| XML 检查点 | 验证 XML 文档中的数据 | 导航到插入 | 检查点 | XML 检查点。 | 检查 XML 节点和属性的值 |
我们将在下一章中学习更多关于检查点的知识。
同步
当测试运行时,它可能无法始终匹配 AUT 的速度,需要等待以下情况。这被称为测试同步。
-
等待直到进度条达到 100%
-
显示状态消息
-
等待直到按钮启用
-
等待直到窗口或弹出窗口显示
在这些情况下,测试可能无法执行下一步或同步超时,导致测试失败。这些问题可以通过 QTP 提供的各种同步技术来解决。
有几种选项可以将测试与 AUT 同步:
-
插入
Wait语句允许测试等待预定义的时间。 -
插入一个同步点或插入
WaitProperty方法,允许测试暂停直到对象属性达到指定的值。 -
Exist语句允许等待直到对象存在或超时。 -
QTP 允许设置网页加载的默认超时时间。
-
通过导航到文件 | 测试 | 运行 | 对象同步超时来增加默认同步超时时间。
-
使用
Sync方法等待网页加载完成。请参阅以下代码:Browser("Mercury Tours").Page("Mercury Tours").Sync小贴士
当 QTP 无法识别对象时,同步点不起作用;使用
exist或wait代替。
Exist 语句
Exist语句允许测试等待窗口打开或对象出现。Exist语句返回一个布尔值,指示对象当前是否存在。
Done = Window("Flight Reservation").Dialog("Flights Table").Exist
Exitsinwaittime =Window("Flight Reservation").Dialog("Flights Table").Exist (10)
第一条语句指示 QuickTest 等待直到默认同步时间。第二条语句等待最多 10 秒,直到Flights Table对话框打开。
小贴士
下载示例代码
您可以从您在 www.packtpub.com 的账户下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了此书,您可以访问 www.packtpub.com/support 并注册,以便将文件直接通过电子邮件发送给您。
Reporter 对象
此对象用于向运行结果发送信息。它具有在运行时用于决定和更改脚本流程控制的多种方法和属性。以下表格展示了 reporter 对象的方法和属性。
Reporter 对象的相关方法 |
Reporter 对象的相关属性 |
|---|---|
ReportEvent 方法ReportNote 方法 |
Filter 属性ReportPath 属性RunStatus 属性 |
让我们看看如何使用这些方法和属性:
它接受四个参数(EventStatus、StepName、Details(Description) 和 [, pathtosavefile]),如下面的代码所示:
Reporter.ReportEvent EventStatus, StepName, Details(Description) [,pathtosavethefile]
EventStatus 以数字或常量的形式显示。这些常量与发送到 运行结果 窗口的消息描述一起显示,如下表所示。
| 0 或 micPass: | 1 或 micFail: | 2 或 micDone: | 3 或 micWarning: |
|---|---|---|---|
| 将传递的消息发送到 运行结果 窗口 | 将失败的消息发送到 运行结果 窗口 | 将完成的消息发送到 运行结果 窗口 | 将警告消息发送到 运行结果 窗口 |
参数列表及其描述如下表所示:
| 参数 | 类型 | 描述 |
|---|---|---|
ReportStepName |
String |
用户希望在 运行结果 窗口中显示的步骤名称 |
Details |
String |
将自定义消息或步骤描述发送到运行结果 |
ImageFilePath |
String |
此参数是可选的。存储图像的格式为 .bmp、.jpeg、.png 和 .gif 格式 |
以下是如何使用 reporter 对象的示例:
chk = Window("Flight Reservation").WinButton("FLIGHT").Check (CheckPoint("FLIGHT_2"))
if(chk = True) then
Reporter.ReportEvent micPass, "Verify Flight CheckPoint","Button is enabled"
else
'msgbox "Fail"
Reporter.ReportEvent micFail, "Verify Flight CheckPoint ","Button is disabled"
end if
Reporter.RunStatus 对象
Reporter.RunStatus 对象检索测试的当前运行状态。以下示例演示了如何检索失败时的值,然后退出测试:
If Reporter.RunStatus = micFail Then ExitTest
此方法还允许将 RunStatus 设置如下所示:
Reporter.RunStatus = micPass
启用或禁用模式设置:
CurrentMode = Reporter.Filter To set the mode: Reporter.Filter = NewMode
模式可以是以下值之一,如下表所示:
| 模式 | 描述 |
|---|---|
0 或 rfEnableAll 默认。 |
在运行结果中显示所有事件 |
1 或 rfEnableErrorsAndWarnings |
在运行结果中显示警告或失败状态 |
2 或 rfEnableErrorsOnly |
在运行结果中显示失败状态 |
3 或 rfDisableAll |
在运行结果中不显示任何事件 |
动作
一个动作是一组执行任务(s)的语句;将测试分解为动作,以将功能分解成更小、更易于管理的脚本。
动作的目的
-
提供将脚本分解为可管理部分的分解
-
提高可重用性
操作类型
-
不可重用操作:它们在同一测试中只能调用一次,且不能在其他测试中使用。
-
可重用操作:可重用操作可以在同一测试中多次使用,也可以在其他测试中使用。
-
外部操作:外部操作定义在另一个测试中,并在调用测试时作为只读使用,可以被存储的测试修改。
错误处理
错误处理是一个重要的方面,它允许从错误条件中干净地恢复。QTP 在出现错误时提供了各种选项。
当运行会话中出现错误时,转到文件 | 设置 | 运行 | 选择;选项包括:
-
弹出消息框:弹出消息框显示用户选择的选项。
-
进入下一个测试迭代:跳过当前迭代并进入下一个。
-
停止运行:停止测试执行。
-
进入下一步:跳过当前步骤并进入下一步。
通过指定此操作,测试将退出错误条件并按照所选选项继续。QTP 还提供了恢复机制。使用 VBScript,我们可以使用 VBScript 的 ERR 对象处理各种错误情况。我们将在本书的后续章节中看到如何使用它。
参数化
参数是一个变量,它保存一个或多个值。参数化允许在执行测试时替换值。QTP 使用datatable来参数化测试。可以使用全局或局部工作表进行参数化:
Dialog("Login").WinEdit("Agent Name:").Set DataTable("Name", dtGlobalSheet) 'Name is column name in datatable and retrieving the data from global sheet

在DataTable或任何外部数据源中定义的数据允许在测试针对数据源中的多行运行时参数化测试。参数化有助于使测试迭代化。
环境变量
QTP 允许使用环境变量配置测试。QTP 提供了内置变量,并允许用户定义变量。可以通过导航到测试 | 设置 | 环境 | 从下拉菜单中选择内置来查看内置环境变量。
以下示例创建了一个名为MyVariable的新用户定义变量,其值为15,然后检索变量值并将其存储在MyValue变量中:
Environment.Value("MyVariable")=10
testvalue = Environment.Value("MyVariable")
我们可以使用以下代码创建Environment变量,并通过导航到测试 | 设置 | 环境 | 选择用户定义选项来添加它。从加载变量设置导出文件,从外部文件设置 XML。使用浏览选项添加它。环境变量文件必须是 XML 文件;使用以下语法:
<Environment>
<Variable>
<Name>TestEnv</Name>
<!-- other environments are QA, Test and Dev -- >
<Value>Staging</Value>
</Variable>
</Environment>
QTP 允许使用命令Environment.LoadFromFile(Path)加载指定的环境变量文件。
以下示例加载了Environment.xml文件:
Environment.LoadFromFile("C:\Environment.xml")
'Check if an External Environment file is loaded and if not, load it.
fileName = Environment.ExternalFileName
If (fileName = "") Then
Environment.LoadFromFile("C:\Environment.xml")
End If
'display value of one of the Environment variables from the External file
msgbox Environment("TestEnv")
摘要
本章的关键主题是学习如何创建可靠和可重用的脚本和概念。较小的代码示例展示了这些概念的使用方法。本章涵盖了创建脚本并使用检查点、参数化、环境变量分割操作以及向运行结果窗口添加报告对象来通知结果所需的步骤。在下一章中,关键讨论将围绕使用代码构建关键特性,这些代码可以用于开发可在框架中使用的组件。
第三章。创建框架的基本构建块
在上一章中,我们看到了创建脚本所需的 QTP 特性。为了设计框架及其组件,我们需要设计可重用的代码块,除了 QTP 特性之外。代码块的关键特性如下:
-
手动检查点:这是一个可重用的函数,它在运行时检查属性是否如预期匹配
-
手动同步:这是一个可重用的函数,它等待直到指定的属性改变
-
描述性编程:这为测试脚本提供了对象标识属性以创建对象描述或创建描述本身
-
正则表达式:这是一个用于匹配模式的文本字符串,并允许我们定义遵循该模式的对象
-
使用 Err 对象和 Exit 语句进行错误处理:也称为异常处理,它指导我们如何从异常事件中退出并优雅地退出这些条件
-
函数、子程序和过程:函数和子程序使我们能够使脚本模块化和可重用
VBScript – 创建代码块的关键特性
VBScript 是一种易于学习且功能强大的脚本语言。它用于开发脚本以执行简单和复杂的基于对象的任务,即使没有之前的编程经验。在专家视图中工作,请使用以下一般的 VBScript 语法规则和指南:
-
大小写敏感度:VBScript 不会区分大写和小写的单词。默认情况下,它不区分大小写,例如,在常量、变量、对象和方法名称中。以下两个语句是相同的:
Browser("Customer").page("Customer").weblist("date").select "31" Browser("Customer").page("Customer").WebList("date").Select "31" -
文本字符串:我们可以通过在文本字符串前后添加双引号来定义一个字符串。在以下示例中,使用双引号分配了字符串值:
Dim objtype= "WinButton" or objtype= "WinButton"日期字符串:我们可以在日期值前后添加井号来定义日期;例如:
today = #7/10/2013# or Dim today = #7/10/2013# -
变量:变量用于存储字符串、整数、日期、数组和对象。我们可以指定变量来引用测试对象或使用或不使用
Dim存储简单值。如果使用,则必须在脚本中的任何其他语句之前出现Option Explicit语句。当声明Option Explicit语句时,它强制我们使用Dim、Private、Public或ReDim语句显式声明变量;否则,将发生错误。要指定一个变量来引用对象,请使用以下语法的
Set语句:Set ObjectVar = ObjectHierarchy Set UserEditBox = Browser("email").Page("email").WebEdit("username") UserEditBox.Set "John"不要使用
Set语句来指定一个包含简单值(如字符串或数字)的变量。下面的例子展示了如何为简单值定义一个变量:MyVar = Browser("email").Page("email").WebEdit("username").GetTOProperty("text")或者也可以定义为:
Dim Myvar = Browser("email").Page("email").WebEdit("username").GetTOProperty("text") -
注释:输入
rem或使用撇号(')来添加注释。 -
空格:VBScript 会忽略空格;它们只是增强了代码的清晰度和可读性。
-
括号:如果被调用的函数返回值,则在参数周围使用括号。
以下示例需要将方法参数放在括号内,因为它返回值:
Set WebEditObj = Browser("Mercury").Page("Mercury").WebTable("table").ChildItem (8, 2, "WebEdit", 0) WebEditObj.Set "name"以下示例需要将方法参数放在括号内,因为使用了Call。
Call RunAction("BookFlight", oneIteration)以下示例需要将方法参数放在括号内,因为它们返回检查点的值:
result = Browser("Customer").Page("Customer").Check (CheckPoint("MyProperty"))以下示例不需要将
Click方法参数放在括号内,因为它们不返回任何值:Browser("Mercury Tours").Page("Method of Payment").WebTable("FirstName").Click
VBScript 过程
在 VBScript 中,有两种类型的子过程:
-
子过程
-
函数过程
子过程
子过程以Sub语句开始,以End Sub语句结束。Sub接受参数但不返回值。以下是一个代码片段的示例:
Sub subSUM(a,b)
print a+b
End Sub
函数过程
函数过程以Function语句开始,以End Function语句结束。它可以返回一个值;返回值始终是变体类型。要返回值,将其分配给函数名。以下是一个函数过程的示例:
Function funcSUM(a,b)
FuncSUM = a+b
End Function
检查点
检查点检查页面、对象或文本字符串的特定值或特征,并使测试对象能够识别 AUT 是否正常工作。检查点将预期值(在录制或创建检查点时捕获)与实际值(在运行时捕获)进行比较。
以下脚本使用 Flight 应用程序创建订单;在选择FlyFrom insert检查点后,我们需要验证FLIGHT按钮的enabled属性是否设置为True:

Window("WinFlight").Activate
Window("WinFlight").ActiveX("MaskEdBox").Type "111114"
Window("WinFlight").WinComboBox("FlyFrom:").Select "Frankfurt"
'Insert a checkpoint to verify if button is enabled or not
Window("WinFlight").WinButton("FLIGHT").Check CheckPoint("WINFLIGHT")
'In the preceding checkpoint verify if button is enabled or not
isChkPointPass= Window("WinFlight").WinButton("FLIGHT").Check (CheckPoint("FLIGHT"))
'Note: We have used the bracket around Checkpoint to get the outcome
If isChkPointPass = True Then
'Continue with order of creation
Window("WinFlight").WinComboBox("FlyTo:").Select "Paris"
Window("WinFlight").WinButton("FLIGHT").Click
Window("WinFlight").Dialog("FlightsTable").WinButton("WinOK").Click
Window("WinFlight").WinEdit("Name:").Set "ashish"
Window("WinFlight").WinButton("Insert Order").Click
Else
'Leave the action if a checkpoint fails
ExitAction
End If
输出值
输出值是在测试执行期间从 DataTable 检索或保存到变量或参数中的值。当输出值执行时,Output方法将对象的属性值放入预先指定的列(在创建测试时定义)中,并通过 DataTable 检索。稍后,此值用于验证预期值和实际值;因此,我们可以使用输出值作为检查点。
以下代码片段使用输出值创建检查点:
Window("WinFlight").Activate
Window("WinFlight").ActiveX("MaskEdBox").Type "111114"
Window("WinFlight").WinComboBox("FlyFrom:").Select "Frankfurt"
'Insert an output value to verify if button is enabled or not
Window("WinFlight").WinButton("FLIGHT"). Output CheckPoint("FLIGHT")
'The first column represents from where value is retrieved and the second column represents sheet Global/local
outval= Datatable("WINFLIGHT_Button",dtGlobalSheet)
'Verify the expected and actual values and report them in test results using reporter.reportevent
If outval = True Then
Reporter.ReportEvent micPass,"Verify WinFlight Button", "Match"
else
Reporter.ReportEvent micFail,"Verify WinFlight Button", "The property value does not match with the expected value"
ExitAction
End If
我们还可以使用CheckProperty方法创建一个手动检查点。CheckProperty允许我们使用各种选项,并且我们还可以检查不等条件。
如何使用CheckProperty检查相等条件:
Window("WinFlight").WinButton("FLIGHT").CheckProperty( "enabled", True, 10000)
检查点允许以下选项以确定不同的不等选项:
-
micGreaterThan:此选项验证属性的值是否大于预期值。 -
micLessThan:此选项验证属性的值是否小于预期值。 -
micGreaterThanOrEqual:此选项验证属性的值是否大于或等于预期值。 -
micLessThanOrEqual:此选项验证属性的值是否小于或等于预期值。 -
micNotEqual:此选项验证属性的值是否不等于预期值。以下示例演示了如何使用不等选项:
Window("WinFlight").WinComboBox("FlyTo:").CheckProperty("items count", micGreaterThanOrEqual(10), 10000) -
micRegExpMatch:CheckProperty还允许我们使用正则表达式。micRegExpMatch选项验证属性值是否与正则表达式匹配,如下例所示,以及如何使用正则表达式与CheckProperty一起使用:Window("WinFlight").WinEdit("Order No:").CheckProperty ("text",micRegExpMatch("\d{1,3}"),10000) Creating checkpoint using GetROPropertyGetROProperty从自动化测试对象(AUT)的运行时对象中返回指定标识属性的当前值。我们可以使用GetROProperty来创建检查点。使用此检查点,我们将获取运行时属性,并且我们可以将其与预期值进行比较,如下例所示:Required. A String value. Property to retrieve from the object. Required. A String value. Property to retrieve from the object. 'We are retrieving the value of enable property of the FLIGHT Button and comparing it with expected value thus serves as a check to take a further action Pvalue =Window("WinFlight").WinButton("FLIGHT").GetRoProperty("enabled") If Pvalue = True Then 'Create the order Else 'Exit the Test ExitTest End If
当我们设计框架及其组件时,我们需要创建手动检查点以实现可重用性;一个良好的做法是将它们创建为可重用函数。
同步
QTP 和 AUT 在某个点上连接或握手以匹配它们的速度,以便事件发生并完成一系列动作。
速度不匹配、延迟、等待属性变化、对象变化和事件发生会导致脚本执行速度不匹配,从而导致自动化测试对象(AUT)出现同步问题,例如,脚本必须等待页面加载完成。默认对象同步时间为 20 秒,但我们可以通过导航到文件 | 测试设置 | 运行 | 对象同步超时来更改它。
将对象同步超时从20秒更改为2秒,如图所示:

现在我们已经更改了对象同步超时值,我们将运行以下脚本:
'Open the Flight Reservation login window and create the script
Dialog("DialogLogin").WinEdit("AgentName").Set "ashish"
Dialog("DialogLogin").WinEdit("AgentPassword").SetSecure "51d84ff2108dc473a416b19e1fed478fab95ca75"
Dialog("DialogLogin").WinButton("WinOK").Click
'The script will fail at this step, the object synchronization is 2 seconds but window takes more time to open; hence script fails
Window("WinFlight").Activate
为了实现同步,我们引入了一些等待脚本,它们等待指定的时间。请参考以下代码片段:
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("AgentName").Set "ashish"
Dialog("DialogLogin").WinEdit("AgentPassword").SetSecure "51d84ff2108dc473a416b19e1fed478fab95ca75"
Dialog("DialogLogin").WinButton("WinOK").Click
'The script will fail at this step. To avoid this, insert a wait statement
wait 10'Window("WinFlight").Activate
wait语句告诉 QTP 等待预定义的时间量,例如,10 秒。在这里,以下情况可能发生:
-
自动测试对象(AUT)已准备好执行下一步,但脚本仍在等待指定的时间
-
等待时间已过,但自动化测试对象(AUT)仍然没有准备好执行下一步
在这两种情况下,静态等待都不是一个好的选择。根据某些必须完成的属性或事件等待适当的时间称为动态同步。
动态同步
动态同步允许等待对象属性变化或直到超时,如下例所示:
Window("WinFlight").ActiveX("MaskEdBox").Type "111114"
Window("WinFlight").WinComboBox("FlyFrom:").Select "Frankfurt"
Window("WinFlight").WinComboBox("FlyTo:").Select "Los Angeles"
Window("WinFlight").WinButton("FLIGHT").Click
Window("WinFlight").Dialog("FlightsTable").WinButton("WinOK").Click
Window("WinFlight").WinEdit("Name:").Set "ashish"
Window("WinFlight").WinButton("Insert Order").Click
'Window("WinFlight").WinButton("Button").Click
'When QTP tries to execute the following statement, application will not allow to click on the button since it is waiting for progress bar to reach 100% and display the message Insert Done...
'Here script will fail
'We need to insert the dynamic synchronization point; this waits until the text changes to Insert Done...
'Window("WinFlight").ActiveX("ThreedPanelControl").WaitProperty "text", "Insert Done...", 10000
可以使用“插入同步点”或手动通过输入来添加WaitProperty方法。
除了使用WaitProperty之外,我们还可以使用以下代码创建同步点:
Set Object = Window("WinFlight").ActiveX("ThreedPanelControl")
Set WinsObject = Window("WinFlight")
'It accepts the object with its property and value. You have to wait along with timeout
Function ManualSyncPoint (Object,propertyname, propertyval,timeout )
Do
If Object.GetROProperty(propertyname) =propertyval then
'if propertyname and propertyval match, come out of the loop and execute next step
Exit Do
else
wait(1)
end if
Loop While (i <= timeout)
End Function
'In the preceding method we have used the static wait; we can implement it without using wait statement as well
Example 2:
Function ManualSyncPoint2(Object ,propertyname, propertyval, timeout )
sttimer = Timer
'Timer allows to get the number of seconds elapsed since midnight (12:00 AM)
Do
If Object.GetROProperty(propertyname) = propertyval then
Exit Do
else
end if
endtimer = Timer
'The difference between the two timer objects provides the number of seconds we need to determine for timeout
Loop While ( int (endtimer-sttimer) <= -timeout)
End Function
'Function that allows to wait till object exists
Function WaitTillExists(Object, timeout )
loadtimer = Timer
Do
isObjectExists = Object.Exist
If isObjectExists = true Then
Exit Do
else
End If
completetimer = Timer
Loop While(completetimer-loadtimer <= timeout)
End Function
'Now we will use these functions in our scripts; refer to the following script
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("AgentName").Set "ashish"
Dialog("DialogLogin").WinEdit("Password").SetSecure "51d84ff2108dc473a416b19e1fed478fab95ca75"
Dialog("DialogLogin").WinButton("WinOK").Click
' wait
'Go to the test settings and make object synchronization time to 2 sec
WaitTillExists WinsObject, 10
Window("WinFlight").Activate
Window("WinFlight").ActiveX("MaskEdBox").Type "111114"
Window("WinFlight").WinComboBox("FlyFrom:").Select "Frankfurt"
Window("WinFlight").WinComboBox("FlyTo:").Select "Los Angeles"
Window("WinFlight").WinButton("FLIGHT").Click
Window("WinFlight").Dialog("FlightsTable").WinButton("WinOK").Click
Window("WinFlight").WinEdit("Name:").Set "ashish"
Window("WinFlight").WinButton("Insert Order").Click
Window("WinFlight").WinButton("Button").Click
'When QTP tries to execute the following statement, the application will not allow to click on the button since it is waiting for progress bar to reach 100% and display the message Insert Done...
'Here script will fail
'We need to insert the dynamic synchronization point
Window("WinFlight").ActiveX("ThreedPanelControl").WaitProperty "text", "Insert Done...", 5000
'The preceding statement waits till the text property changes to Insert Done... and waits for upto 10 secs
If ManualSyncPoint1(Object ,"text","Insert Done…",10) = true then
'do nothing
else
ExitTest
end if
Window("WinFlight").WinButton("Button").Click
描述性编程
QTP 通过存储在 OR 中的对象属性来识别对象。当在测试脚本中创建对象描述时,这种方法被称为描述性编程。在这种脚本创建方法中,对象不会被存储在 OR 中。
描述性编程可以通过两种方式实现:
-
静态编程:对象的描述直接提供到脚本中
-
动态编程:使用 QTP 的描述对象创建对象的描述
静态编程
静态描述性编程的例子如下所示:
'Add object description as property value pair
Dialog("regexpwndclass:=Login").Activate
Dialog("regexpwndclass:=Login").WinEdit("regexpwndclass:=Edit","attached text:=AgentName").Set "ashish"
Dialog("regexpwndclass:=Login").WinEdit("regexpwndclass:=Edit","attached text:=AgentPassword").Set "mercury"
Dialog("regexpwndclass:=Login").WinButton("regexpwndtitle:=OK").Click
'The multiple property and value pair is provided in the object description; property value pair should be comma separated
Method 2: Define Description as constant
Note:
Constant represents the literal value and gives it a name that is not allowed to change at time of script execution. Declare constants for use in place of literal values. For example, Const Env = "QA"
Define Constant
Name of the constant and expression; expression is Literal or another constant, or any combination that includes all arithmetic or logical operators
Constant can be declared as Public or Private. A variable that is declared as a constant is available to all procedures in all scripts. Not allowed in procedures. The Private keyword is used at script level to declare constants available only within the script where the declaration is made. Not allowed in procedures
Const Dailoglogin ="regexpwndtitle:=Login"
Const agent = "attached text:=AgentName"
Const password = "attached text:=Password:"
Const okButton ="text:=OK"
Dialog(Dialoglogin).Activate
Dialog(Dialoglogin).WinEdit(agent).Set "ashish"
Dialog(Dialoglogin).WinButton(okButton).Click
Method 3: Substitution of property values shown as follows
dialogname ="login"
agentname ="AgentName"
passwdname ="Password:"
buttonlabel="OK"
Dialog("regexpwndtitle:="&dialogname).Activate
Dialog("regexpwndtitle:="&dialogname).WinEdit("attached text:="&agentname).Set "ashish"
Dialog("regexpwndtitle:="&dialogname).WinEdit("attached text:="&passwdname).Set "mercury"
Dialog("regexpwndtitle:="&dialogname).WinButton("text:="& buttonlabel).Click
动态编程
QTP 允许使用Description对象及其Create方法来创建对象描述,并将其作为参数传递以创建脚本。
以下是一个相同的例子:
Set diaDesc = Description.Create()
diaDesc("micclass").value="Dialog"
diaDesc("regexpwndtitle").Value ="Login"
Set btnDesc=Description.Create()
btnDesc("micclass").value="WinButton"
btnDesc("text").value="OK"
Set txtDesc = Description.Create()
txtDesc("micclass").value="WinEdit"
txtDesc("attached text").Value ="AgentName"
Set pwdDesc = Description.Create()
pwdDesc("micclass").value="WinEdit"
pwdDesc("attached text").Value ="Password:"
'Use these objects into the scripts shown as follows
Dialog(diaDesc).Activate
Dialog(diaDesc).WinEdit(txtDesc).Set "ashish"
Dialog(diaDesc).WinEdit(pwdDesc).Set "mercury"
Dialog(diaDesc).WinButton(btnDesc).Click
具有相同识别属性的测试对象被称为重复对象。序号标识符允许我们使用index和location属性来识别重复对象。index表示从左到右和从上到下的对象顺序。location表示从左上角到底部和从右上角到底部的对象。
'Ordinal Identifier stats with 0
Browser("email").Page("email").WebEdit("name:=FNAME", "index:=0").Set "Ashish1"
Browser("email").Page("email").WebEdit("name:=FNAME", "index:=1").Set "Ashish2"
Browser("email").Page("email").WebEdit("name:=FNAME", "index:=2").Set "Ashish3"
Browser("email").Page("email").WebEdit("name:=FNAME", "index:=3").Set "Ashish4"
运行脚本后的结果如下:

Browser("email").Page("email").WebEdit("name:=FNAME", "location:=0").Set "Ashish1"
Browser("email").Page("email").WebEdit("name:=FNAME", "location:=1").Set "Ashish2"
Browser("email").Page("email").WebEdit("name:=FNAME", "location:=2").Set "Ashish3"
Browser("email").Page("email").WebEdit("name:=FNAME", "location:=3").Set "Ashish4"
运行脚本后的结果如下

描述性编程使我们能够处理动态对象;这是一个测试对象在运行时才存在的情况,因此我们无法在 OR 中存储动态对象。例如,一个文本框是根据网页中的用户 ID 在运行时生成的,对象的名称遵循约定 edit_xxx,即 edit_123455\。
代码在上一页提供;现在我们将编写代码来设置如下代码片段所示的价值:
Code = getCode() ' getCode is a function that's return the code given in previous page, we can use that code to create the object description for webEdit
Browser("email").Page("email").WebEdit("name:=text_"&Code).Set "jonh"
描述性编程的一个用途是它允许我们在运行时找到对象(s)并对其执行以下操作:
Set buttonDesc=Description.Create()
buttonDesc("micclass").value="WinButton"
Set winAll=Window("regexpwndtitle:=Flight Reservation").ChildObjects(buttonDesc)
cnt=winAll.count
MsgBox "Total number of Buttons: "&cnt
For i=0 to cnt-1
MsgBox winAll(i).getroproperty("text")
If winAll(i).Getroproperty("text")="FLIGHT" Then
winAll(i).Click
End If
Next
正则表达式
正则表达式(缩写为 regex 或 regexp)是一系列文本字符,其中一些被认为是具有符号意义的元字符,而另一些则具有其字面意义,它们一起自动识别给定的模式。
当对象本质上是动态的,我们无法在 OR 中存储每个遵循模式的对象时,正则表达式非常有用。在航班预订应用程序中,我们可以通过订单号打开任何现有订单并发送传真。当传真窗口打开时,窗口的标题包含订单号;当我们想要以不同的订单号打开传真窗口时,这将会引起问题,因为窗口不再是相同的。在这种情况下,我们可以使用正则表达式。参考以下截图;对象的识别属性是传真订单号 11。在这里,我们将文本属性转换为正则表达式,以将属性识别为模式而不是固定值。
下面的屏幕截图中的正则表达式匹配一个数字可能从1到3变化的模式。这意味着它用于验证从 0 到 999 的传真窗口标题。

描述性编程中的正则表达式
在早期的屏幕截图中,我们看到了一旦我们将文本属性更改为正则表达式,QTP 就能够识别从 0 到 999 的顺序号的对象。我们可以在对象描述中使用正则表达式,如下面的代码所示:
Window("WinFlight").Dialog("regexpwndclass:=#32770", "text:=Fax Order No\. \d{1,3}").Activex("progid:=MSMask.MaskEdBox.1").Type "1111111111"
检查点中的正则表达式
检查点允许我们使用正则表达式进行模式匹配。要在检查点中使用正则表达式,请执行以下操作:
-
在文本检查点属性窗口中点击参数选项。
-
点击
。 -
在参数选项中检查正则表达式选项。
-
点击确定并将参数更改为正则表达式(在数据表中)如图所示。

CheckProperty 中的正则表达式
CheckProperty允许我们使用正则表达式和micRegExpMatch比较值,如下面的代码片段所示:
'Verify whether the order number is numeric
Window("WinFlight").WinEdit("Order No:").CheckProperty ("text",micRegExpMatch("\d{1,3}"),10000)
错误处理
异常处理是处理中断测试执行正常流程的异常或异常事件的方法。例如,当浮点数除以零(0)时,它将停止执行并显示错误消息,如下面的代码片段所示:
Type in the QTP editor
Result = 5 / 0
'When test runs the preceding line, it will display Error Division by zero
VBScript 中的Err对象包含运行时错误的详细信息,即使在运行时出现错误,也能继续执行。
如果脚本中缺少On Error Resume Next语句,任何运行时错误都会停止执行并显示错误消息,如下所示:
On Error Resume Next
Result = 5 / 0
'The above line will not display any error
使用On Error Resume Next语句允许我们继续处理异常,但有必要使用Err对象处理错误,并从错误条件中干净地退出。
Err对象的属性如下:
-
描述属性 -
帮助上下文属性 -
帮助文件属性 -
数字属性 -
源属性
Err对象的方法如下:
-
清除方法 -
抛出方法
On Error Resume Next 'Enables the Err object to deal with error
'Raise an overflow error.
Err.Raise 6
MsgBox "Error number is" & CStr(Err.Number) & "--" & Cstr(Err.Description))
'Clear the error.
Err.Clear
如果使用了On Error Resume Next,请使用On Error GoTo 0来禁用错误处理。
以下代码片段展示了如何使用Err对象进行错误处理的示例:
On Error Resume Next
Const ForReading = 1
Dim fso, theFile, retstring
Set fileso = CreateObject("Scripting.FileSystemObject")
Set theFile = fileso.OpenTextFile("c:\FilenotFound.txt", ForReading)
'Verify if error number of the Err object using its property number
If Err.number <> 0 then
'Error send there is no file exists by FilenotFound.txt
MsgBox Cstr(Err.number & "--"& Cstr(Err.Description)
ExitAction(-1)
else
'Do While theFile.AtEndOfStream <> True
Do until theFile.AtEndOfStream
str = theFile.ReadLine()
MsgBox str
Loop
theFile.Close
end if
QTP 中的Exit语句非常重要;它们允许我们优雅地退出循环、操作、迭代、组件和测试。
以下显示了不同类型的Exit语句:
-
退出循环:此语句允许我们从Do循环语句中退出。 -
退出循环:此语句允许我们从For循环中退出。 -
退出函数:此语句允许我们从被调用的函数过程中退出。 -
退出属性:此语句允许我们从属性过程中退出。 -
Exit Sub: 这条语句允许我们从被调用的Sub过程中退出。 -
ExitAction: 这条语句允许我们从当前动作的迭代中退出。 -
ExitTest: 这条语句允许我们退出整个 QTP 或 质量中心(QC)业务流程测试,无论运行迭代设置如何。 -
ExitTestIteration: 这条语句允许我们退出测试迭代或 QC 的业务流程测试,并继续到下一个迭代。如果没有下一个迭代,它将停止执行。
ExitActionIteration 的返回值在 运行结果 窗口中显示。
-
ExitComponent: 这条语句允许我们退出当前组件的运行。在 业务流程测试(BPT)中,每个组件(脚本或业务)与 QTP 测试的单个动作相同。业务流程逐个运行每个组件。QC 将组件加载到 QTP 并开始运行。一旦运行完成,测试中的下一个组件将被加载,所有结果都将汇总成一个单独的测试结果摘要。
-
ExitComponentIteration: 这条语句允许我们退出当前组件迭代。
以下示例演示了当检查点失败时使用 Exit 语句的情况:
res = Browser("Mercury").Page("Mercury").WebEdit("userName").Check ( CheckPoint("Name") )
If res = False Then
'ExitActionIteration /ExitAction / /ExitTestIteration /ExitTest /ExitComponentIteration /ExitComponent
'We can use any one of them to gracefully exit based on how test is executing.
End If
恢复场景 - 概述
在执行过程中,任何意外事件或错误条件导致自动测试工具(AUT)崩溃,都需要进行恢复。为了处理这些情况,QTP 允许我们定义恢复场景,并将它们与测试关联起来。当触发事件发生时,恢复场景会激活特定的恢复操作。
恢复场景管理器允许我们定义恢复场景,包括意外事件和运行会话期间要恢复的操作。例如,出现意外的弹出消息,通过在弹出窗口中点击 确定 按钮来恢复恢复场景。
恢复场景具有以下元素:
-
触发事件:任何突然干扰测试运行正常流程的事件,例如,测试执行期间弹出对话框。
-
恢复操作:恢复选项允许 QTP 在触发事件阻碍测试执行后继续运行测试或其组件。例如,关闭弹出窗口或调用重启窗口。
-
恢复后-选项:在执行恢复操作之后,QTP 提供了一些选项,例如调用自定义函数、执行相同的步骤或执行测试或组件中的下一个步骤。
在创建恢复场景后,我们可以将它们与选定的组件/测试关联起来。因此,如果在运行会话中发生触发事件,QTP 将执行适当的场景。
摘要
在本章中,我们探讨了各种概念和代码块。关键是要理解,除了 QTP 功能之外,我们还需要其他支持整个框架设计和架构的组件。创建代码块的一个关键方面是提高其可重用性,并对框架设计的每个功能产生影响。下一章将讨论设计和实现测试自动化框架。
第四章:理解和创建框架
本章提供了创建测试自动化框架的详细方法和指导。
在 QTP 中创建框架需要了解以下内容:
-
VBScript 基础知识、控制结构、循环和内置函数
-
设计各种框架的基本概念和方法
-
帮助创建框架实用工具的编程结构
使用 VBScript 进行编程
熟悉 Visual Basic 脚本对于创建框架至关重要。了解 VBScript 中的简单语句、控制结构、循环和内置函数,使我们能够增强测试脚本并使其更健壮;它还允许我们与外部资源交互。本节描述了在设计框架过程中有用的 VBScript 功能。
使用 VBScript
QTP 使用 VBScript 作为脚本语言。VBScript 允许脚本处理不属于 QTP 本身的资源,例如文件系统和外部的数据源(Excel、数据库等)。VBScript 允许我们定义函数过程;它提供许多内置函数,有助于创建可重用函数。VBScript 支持正则表达式,有助于验证和验证。由于它是一种轻量级语言,框架设计者从中受益。
VBScript 数据类型
变体是 VBScript 中唯一的数据类型。根据其声明和使用方式,变体可以包含不同类型的信息。它可以包含数字、常量、日期、字符串和布尔值。
以下是一个变体的子类型列表:
| 子类型 | 描述 | 范围 |
|---|---|---|
Empty |
变体未初始化 | 对于数值变量为 0 或对于字符串变量为零长度 |
Null |
变体最初不包含有效数据 | 不包含数据 |
Boolean |
真 或 假 | |
Byte |
小整数 | 0-255 |
Integer |
整数 | 从 -32,768 到 32,767 |
Currency |
货币 | 从 -922,337,203,685,477.5808 到 922,337,203,685,477.5807 |
Long |
长整数 | 从 -2,147,483,648 到 2,147,483,647 |
Single |
单精度浮点数 | 对于负值,从 -3.402823E38 到 -1.401298E-45,对于正值,从 1.401298E-45 到 3.402823E38 |
Double |
双精度浮点数 | 对于负值,从 1.79769313486232E308 到 4.94065645841247E-324,对于正值,从 4.94065645841247E-324 到 1.79769313486232E308 |
Date (Time) |
表示日期的数字 | 从 100 年 1 月 1 日到 9999 年 12 月 31 日 |
String |
表示字符 | 包含可变长度的字符串,长度约为 20 亿 |
Object |
包含一个对象 | |
Error |
包含一个错误对象 |
VBScript 中的运算符
运算符在创建表达式时很有用;这些表达式通过算术、比较和逻辑运算符创建。在 VBScript 中,我们可以将运算符分为四大类:
-
数学
-
比较
-
连接
-
逻辑
| 数学 | 符号 | 比较 | 符号 | 逻辑 | 符号 |
|---|---|---|---|---|---|
| 指数 | ^ |
等于 | = |
逻辑否定 | Not |
| 尿素否定 | - |
不等式 | <> |
逻辑合取 | And |
| 乘法 | * |
小于 | < |
逻辑析取 | OR |
| 除法 | / |
大于 | > |
逻辑排除 | XOR |
| 整数除法 | \ |
小于等于 | <= |
逻辑等价 | EQV |
| 模数 | MOD |
大于等于 | >= |
逻辑蕴涵 | IMP |
| 加法 | + |
对象等价** | Is |
||
| 减法 | - |
||||
| 连接 | & |
注意
整数除法将两个数字相除并返回一个整数结果,例如,5/2 的结果将是 2 而不是 2.5。
模数或余数运算符将操作数 1 除以操作数 2(将浮点数四舍五入为整数)并返回余数,例如,5 MOD 2 的结果将是 1。
对象等价比较两个对象引用变量。如果 object1 和 object2 都引用了同一个对象,则结果为True;如果它们不引用同一个对象,则结果为False。
添加表达式的示例
表达式是由显式值、常量、变量、运算符和函数组成的组合,这些值根据特定编程/脚本语言的特定优先级和关联规则进行解释。
控制结构和循环
控制结构根据表达式的值有条件地执行一组语句。有四种控制执行流程的结构,如下表所示:
| If (condition)statement1End If | If condition Then statements [Else else statements]End If | If condition Then[statements][ElseIf condition Then[elseif statements]][Else[else statements]]End If | Select Case expression[Case expression list[statements]][Case Else[else statements]]End Select |
|---|
以下给出了If和else控制语句的示例:
If True Then
Reporter.ReportEvent micPass,"Name of the step", "Details..."
Else
Reporter.ReportEvent micFail, "Name of the step", "Details..."
End If
If elseif … and end if
color ="b"
If color ="r" Then
msgbox "red"
elseif color ="g" then
msgbox "green"
elseif color="b" then
msgbox "blue"
else
msgbox "invalid color..."
End If
以下是一个Select案例的示例:
Dim Color, bgcolor
Select Case Color
Case "red" bgColor = "red"
Case "green" bgColor = "green"
Case "blue" bgColor = "blue"
Case Else MsgBox "pick another color"
End select
Msgbox "You have Selected the "& bgcolor
当给定条件为True时,运行前面的代码行将执行一系列语句。
使用循环
循环执行一次指定的语句序列,但可能连续多次执行。VBScript 允许以下表格所示的四种循环结构:
| While … Wend | Do…Loop | For…Next | For each…Next |
|---|---|---|---|
While condition[statements]Wend |
`Do [{While | Until} condition][statements][Exit Do][statements]LoopDo[statements][Exit Do][statements]Loop [{While | Until} condition]` |
以下为While … Wend使用示例:
'Print 10 random numbers
counter = 0 'Initialize the counter
While counter < 10
print Cint( rnd() * 100 )
counter = counter + 1 'Increment the counter
Wend
While…Wend循环的一个缺点是没有exit语句来终止循环,但其他循环结构允许我们从循环中退出。
Do Loop
Do...Loop在不确定的次数上运行语句。语句要么在条件为真时重复,要么直到它变为真。
以下为Do Loops使用示例:
'Execute the loop until the response until CANCEL button is clicked
Usages 1
Do Until DefResp = vbNo
MyNum = Int (6 * Rnd + 1)
'Generate a random number between 1 and 6.
DefResp = MsgBox (MyNum & "Do you want another number?", vbYesNo)
'The msgbox displays generated random number and OK and Cancel button
Loop
Usages 2
Do while not DefResp = vbNo
MyNum = Int (6 * Rnd + 1)
DefResp = MsgBox (MyNum & "Do you want another number?", vbYesNo)
Loop
Usages 3
Do
MyNum = Int (6 * Rnd + 1)
DefResp = MsgBox (MyNum & "Do you want another number?", vbYesNo)
Loop until DefResp = vbNo
Do Loop有两种变体;我们可以使用Do或Loop与while或until条件一起使用。当我们使用Do与while或until条件时,执行首先验证条件,然后进入循环;参见图例 1。在后一种情况,即图例 3 中,第一个循环执行一次,然后检查条件。
For Next循环在预定义的次数上迭代执行语句。参见图例。
ToProperties方法返回测试对象属性集合。
set Pcoll =
Dialog("DialogLogin").WinEdit("EditAgentName:").GetTOProperties()
For i = 0 to coll.count() – 1
'Count method return the numbers of properties
-print "Item is " & Pcoll.item(i)
Next
上述代码集的结果如下:
Item is Edit
Item is Agent Name:
Refer the above results and compare the properties of the object are same in the following image.
参考以下屏幕截图:

For each … Next循环对数组或集合中的每个元素迭代执行语句。
Dim dicObj创建了一个字典变量,如下所示:
Set city = CreateObject("Scripting.Dictionary") 'Creates Dictionary Object
'Dictionary stores data key, item (key – value) pairs.
'Add keys and items.
dicObj.Add "a", "Atlanta"
dicObj.Add "b", "Paris"
dicObj.Add "c", "New Delhi"
'Keys is a method that returns an array or collection containing all existing keys in a Dictionary object.
For each keyitem in d.Keys
print keyitem
Next
介绍框架
框架被定义为对相互关联组件的广泛概述、指南或框架,支持特定目标的一种特定方法,并作为可以按需通过添加或删除组件来增强的指南。框架是一个支持或为创建或扩展测试脚本提供指南的工作或概念模型,以实现测试自动化,确保维护成本低且易于扩展。
测试自动化框架是一个分层结构,提供了相互关联和交互的机制以实现共同目标。框架还包括实际程序和接口,或提供用于使用框架的实用工具。框架简化了修改、添加和删除脚本和函数的标准方式。它是一个提供可扩展性和可靠性的综合结构,且无需过多努力。
通过选择适合测试自动化的正确框架,可以实现自动化目标。测试自动化的成本包括开发和维护工作。选择合适的框架和技术有助于保持低成本和高影响解决方案。
自动化框架和框架类型
通常,使用各种结构和技术来设计框架。广泛基于这些技术和结构,我们可以将框架分类如下:
-
线性:在这个框架中,脚本以线性方式创建,通常通过录制和回放生成,可能没有或只有轻微的修改。
-
数据驱动:参数化测试并从持久数据源获取数据。数据源可以是测试的内部或外部。
-
模块化:模块化框架旨在在测试和脚本级别实现模块化。模块化框架可以是以下组合之一:
-
测试脚本模块化框架
-
测试库模块化框架
-
-
关键字驱动:关键字驱动框架旨在通过将测试用例与其执行分离来降低维护成本。
-
混合:在这个框架中,使用两种或更多之前模式。
录制和回放
录制是捕获对象及其属性的过程,创建测试对象,并将它们以层次结构存储在对象资源管理器中。为测试对象分配一个逻辑名称,并通过捕获在 GUI 上执行的操作来创建脚本。

前面的截图显示了自动测试对象(AUT)、记录的脚本和对象资源管理器(OR)。自动测试对象包含测试对象。对象资源管理器以层次结构存储测试对象及其标识属性:
记录的脚本带我们通过以下三个测试步骤:
-
点击登录对话框。
-
在代理名称文本框中输入
ashish。 -
输入密码。
一个测试步骤包含具有层次结构、操作和数据值(如适用)的测试对象。在记录自动测试对象上的用户操作时,对象资源管理器的创建和脚本的生成几乎同时发生。这种方法也称为QTP 线性框架方法。在线性框架方法中,脚本以逐步方式记录,不关注可重用性。考虑一个例子,你有一个测试用例用于登录应用程序,搜索一些数据然后登出。在线性框架中,代码看起来像以下示例:
创建 QTP 线性框架的步骤:
-
输入用户名。
-
输入密码。
-
点击确定按钮。
-
输入航班日期。
-
选择飞出(源)。
-
选择飞往(目的地)。
-
点击航班按钮。
-
点击确定按钮。
-
输入名称。
-
点击插入订单按钮。
-
关闭航班预订窗口。
'Login
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("EditAgentName:").Set "ashish" 'Enter the agent name
Dialog("DialogLogin").WinEdit("EditPassword:").SetSecure "51e6911da82a99155f73b209eaeac51a66ef0883" ' Enter password
'Create Order
Window("WinFlight").Activate
Window("WinFlight").ActiveX("MaskEdBox").Type "111114" 'Enter Flight Date
Window("WinFlight").WinComboBox("FlyFrom").Select "London" ' Select Source
Window("WinFlight").WinComboBox("Fly To:").Select "Frankfurt" 'Select destination
Window("WinFlight").WinButton("btnFLIGHT").Click 'Click on flight button
Window("WinFlight").Dialog("FlightTable").WinButton("btnOK").Click 'Click on the OK button
Window("WinFlight").WinEdit("EditName:").Set "Mr. James Anderson" 'Enter the passenger name
Window("WinFlight").WinButton("btnInsertOrder").Click'Click on the Insert Order button
Window("WinFlight").Activate
Window("WinFlight").Close'Click on the close button
如果自动测试对象(AUT)较小,这是创建脚本和使用它们的简单方法,但如果期望 AUT 频繁更改,则不要期望。
线性框架的优缺点
线性框架的优点如下所述:
-
不需要编程或设计的专业知识或经验。创建脚本需要基本了解 QTP。
-
自动在对象库中创建和存储测试对象。
-
这是创建测试自动化脚本最快的方式。
-
这是 simplest 框架,并且易于理解。
-
帮助学习对象并手动创建脚本。
-
可以轻松添加检查点。
线性框架的缺点如下所述:
-
由于脚本以线性方式创建且没有函数,因此不允许重用。
-
数据与脚本绑定;因此,测试是非迭代的,这种方法对于执行多组数据的测试效率低下。每次运行都需要手动更改数据或创建多个脚本副本;不幸的是,这两种技术都效率低下。
-
维护成本非常高,且繁琐,容易出错,因为它需要在所有受影响区域进行更改。
-
需要我们自己添加注释。
数据驱动框架简介
数据驱动框架是一组运行相关多个数据集的测试脚本。此框架为不同数据集提供可重用脚本,并提高测试覆盖率。输入和结果(测试标准)数据值可以存储在一个或多个中央数据源或数据库中;实际格式和组织可以是实现特定的。
要了解数据驱动框架的实现,我们应该了解三个术语:
-
变量
-
参数
-
迭代
变量是一个存储位置,与一个标识符相关联,包含一些已知或未知数量或信息,即值。
参数是一个变量,它作为输入提供给脚本。在 QTP 中,可以通过 datatable 对象实现参数化。datatable 对象表示 QuickTest 设计时数据表及其关联的表和参数。datatable 对象具有各种方法和属性,用于从运行时数据表对象访问数据。
迭代是一个过程,其中参数化脚本从数据源执行预定义次数的测试。
创建数据驱动框架有四个主要步骤:
-
创建一个脚本。
-
定义包含数据的参数。
-
添加代码从数据源获取数据并分配值。
-
修改设置或添加代码以执行所有行或行子集的测试。
在 QTP 中访问数据有两种主要方式:
-
使用
datatable对象 -
使用外部数据源
使用 datatable 对象创建数据驱动脚本:
-
通过录制或手动创建脚本。
-
如以下截图所示,在外部 Excel 表格中定义参数。确保第一行包含参数名称。在后续行中输入数据,如以下截图所示:
![数据驱动框架简介]()
要从外部 Excel 表格中获取数据,请使用 datatable 的 import 方法:
-
使用
datatable对象定义参数 -
要添加数据,通过双击列名来重命名列名。重命名列并按以下截图所示将数据添加到后续行中:
![数据驱动框架简介]()
-
使用数据驱动工具或
datatable对象参数化。将测试数据添加到datatable,将列名添加到标题中,然后双击添加或更改数据表中的列名为参数。 -
使测试脚本迭代。
有两种方法可以使脚本迭代。首先,在测试设置下选择仅运行一次迭代、运行所有行,然后选择从行 n 到行 m 运行:

其次,你也可以通过编程创建运行测试脚本的脚本:
'Set the current row to retrieve the value from datatable
datatable.SetCurrentRow startnum
For i =startnum to endnum 'run the script from row (n) to row (m)
.
.
.
'Move to next row of datatable
datatable.SetNextRow
Next
注意
要运行一次迭代,startnum 和 endnum 应为 1,startnum=endnum=1
要运行所有行的测试,startnum = 1 和 endnum = datatable.GetRowCount。
让我们将所有概念结合起来,对测试进行参数化。在 datatable 中创建测试数据。datatable 有两个参数:参数名和表类型。datatable 有两种类型的表:本地表(与操作相关)和全局表。要从全局表中访问数据,请使用 dtGlobalSheet,要从本地表中访问数据,请使用 dtLocalSheet。请参考以下示例:
Systemutil.Run PathToFlightApp
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("EditAgentName:").Set DataTable("Agent",dtGlobalSheet)
Dialog("DialogLogin").WinEdit("EditPassword:").SetSecure DataTable("Password",dtGlobalSheet)
Dialog("DialogLogin").WinButton("btnOK").Click
Window("WinFlight").ActiveX("MaskEdBox").Type DataTable("FlightDate",dtGlobalSheet)
Window("WinFlight").WinComboBox("FlyFrom").Select DataTable("FlyFrom",dtGlobalSheet)
Window("WinFlight").WinComboBox("Fly To:").Select DataTable("Flyto",dtGlobalSheet)
Window("WinFlight").WinButton("btnFLIGHT").Click
Window("WinFlight").Dialog("FlightTable").WinButton("btnOK").Click
Window("WinFlight").WinEdit("EditName:").Set DataTable("Name", dtGlobalSheet)
Window("WinFlight").WinButton("btnInsertOrder").Click
Window("WinFlight").WinButton("btnButton").Click
Window("WinFlight").Close
以下代码展示了如何使用 datatable 导入和迭代测试:
datatable.Import "c:\FlightData.xls"
' Import the excel to the datatable.
rc = datatable.GetRowCount
'get the row count
For i = 1 to rc
systemutil.Run PathToFlightApp
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("EditAgentName:").Set datatable.Value("Agent")
'Value is DataTable default property. Retrieves or sets the value of the cell in the specified parameter and the current row of the run-time Data Table.
'To find the value use DataTable.Value(ParameterID [, SheetID]) .SheetID Optional. Identifies the sheet to be returned. The SheetID can be the sheet name, index or dtLocalSheet, or dtGlobalSheet.
Dialog("DialogLogin").WinEdit("EditPassword:").SetSecure datatable.Value("Password")
Dialog("DialogLogin").WinButton("btnOK").Click
Window("WinFlight").ActiveX("MaskEdBox").Type datatable.Value("FlightDate")
Window("WinFlight").WinComboBox("FlyFrom").Select datatable.Value("FlyFrom")
Window("WinFlight").WinComboBox("Fly To:").Select datatable.Value("Flyto")
Window("WinFlight").WinButton("btnFLIGHT").Click
Window("WinFlight").Dialog("FlightTable").WinButton("btnOK").Click
Window("WinFlight").WinEdit("EditName:").Set datatable.Value("Name")
Window("WinFlight").WinButton("btnInsertOrder").Click
Window("WinFlight").WinButton("btnButton").Click
Window("WinFlight").Close
datatable.SetNextRow
Next
使用 Excel 应用程序和 VBScript:
Set excelfile = createobject("excel.application")
'Create the excel first before executing script.
'Ensure that excel file is in Closed state.
excelfile.Workbooks.Open "D:\parameter.xls"
set sheet = excelfile.ActiveWorkbook.Worksheets("Sheet1")
'Get the max row occupied in the excel file
Row = sheet.UsedRange.Rows.Count
'Read the data from the excel file
For i= 2 to Row
Username=sheet.cells(i,1).value
Password=sheet.cells(i,2).value
wait 1
Next
'Close the Workbook
excelfile.ActiveWorkbook.Close
'Close Excel
excelfile.Application.Quit
'Release the objects
Set sheet =nothing
Set excelfile = nothing
文件系统对象模型
VBScript 允许你使用 FileSystemObject (FSO) 对象模型处理驱动器、文件夹和文件,以下章节将解释如何使用 FileSystemObject 来操作文件。
文件操作有两种方式:
-
创建和附加文件、从文件中删除数据以及从文件中读取
-
复制、移动和删除文件
以下是从文本文件中读取和写入数据的步骤:
-
创建一个文本文件。
-
向其中写入数据。
-
关闭它。
-
再次打开文本文件。
-
读取文件。
-
关闭它。
以下是一个读取和写入文本文件的示例:
Dim filefso, file1, readfile, s
Const ForReading = 1
'create the object of a File system Object
Set filefso = CreateObject("Scripting.FileSystemObject")
Set file1 = filefso.CreateTextFile("c:\logfile.txt", True)
'Write a line.
fi1e1.WriteLine "Testing FSO"
file1.WriteBlankLines(2)
file1.Close
'Read contents of the text file.
'Reading file
Set readfile = filefso.OpenTextFile("c:\logfile.txt", ForReading)
's = readfile.ReadLine
'iterate the file until end of the file
Do While readfile.AtEndOfStream <> True
retstring = readfile.ReadLine
Loop
ts.Close
下面给出了使用文本文件进行数据驱动测试的示例:
Dim fso, f1, textfile, s
Const ForReading = 1
Set textfile = fso.OpenTextFile("c:\logfile.txt", ForReading)
's = textfile.ReadLine
'iterate the file until end of the file
Do While textfile.AtEndOfStream <> True
retstring = textfile.ReadLine
Dialog("DialogLogin").Activate
Dialog("DialogLogin").WinEdit("EditAgentName:").Set datatable.Value("Agent")
'Value is DataTable default property. Retrieves or sets the value of the cell in the specified parameter and the current row of the run-time Data Table.
'To find the value use DataTable.Value(ParameterID [, SheetID]) .SheetID Optional. Identifies the sheet to be returned. The SheetID can be the sheet name, index or dtLocalSheet, or dtGlobalSheet.
Dialog("DialogLogin").WinEdit("EditPassword:").SetSecure datatable.Value("Password")
Dialog("DialogLogin").WinButton("btnOK").Click
Window("WinFlight").ActiveX("MaskEdBox").Type datatable.Value("FlightDate")
Window("WinFlight").WinComboBox("FlyFrom").Select datatable.Value("FlyFrom")
Window("WinFlight").WinComboBox("FlyTo:").Select datatable.Value("Flyto")
Window("WinFlight").WinButton("btnFLIGHT").Click
Window("WinFlight").Dialog("FlightTable").WinButton("btnOK").Click
Window("WinFlight").WinEdit("EditName:").Set datatable.Value("Name")
Window("WinFlight").WinButton("btnInsertOrder").Click
Window("WinFlight").WinButton("btnButton").Click
Window("WinFlight").Close
Loop
textfile.Close
列出用于在测试文件上执行读写操作的方法如下:
Write |
将数据写入打开的文本文件 |
|---|---|
WriteLine |
将数据写入打开的文本文件,并添加一个换行符 |
WriteBlankLines |
向打开的文本文件写入空白行 |
Read |
从文本文件中读取指定为参数的字符 |
ReadLine |
读取整行,不包括换行符 |
ReadAll |
从文本文件中读取整个数据 |
以下示例演示了文件操作:
Dim filefso, txtfile1, txtfile2, txtfifle3
Set filefso = CreateObject("Scripting.FileSystemObject")
Set txtfile1 = filefso.CreateTextFile("d:\tmp\testfile.txt", True)
'Write a line.
txtfile1.Write ("Writing a text")
'Close the file to writing.
txtfile1.Close
'Moving the file to d:\tmp
'Get a handle of the file in root of d:\.
Set txtfile2 = filefso.GetFile("d:\tmp\testfile.txt")
'Moving the file to tmp directory.
txtfile2.Move ("d:\tmp\testfile.txt")
'Copying the file to temp.
txtfile2.Copy ("d:\temp\testfile.txt")
Set txtfifle2 = filefso.GetFile("d:\tmp\testfile.txt")
Set txtfifle3 = filefso.GetFile("d:\temp\testfile.txt")
'Deleting the files
txtfifle2.Delete
txtfifle3.Delete
以下是一个使用 ADODB 从数据库获取数据的示例:
Set Conn = CreateObject("ADODB.Connection")
'Set the Connection String.
Conn.ConnectionString =
"DSN=QT_Flight32;DBQ=C:\Program Files\Mercury Interactive\QuickTest Professional\samples\flight\app\flight32.mdb;Driver=C:\WINDOWS\system32\odbcjt32.dll;DriverId=281;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;"
'ADODB.Connection
'RecordSet
Conn.Open("DSN=QT_Flight32")
Set rcRecordSet= Conn.Execute("SELECT order_number from Orders order by order_number desc")
rcRecordSet.MoveFirst
var_order_num = rcRecordSet.fields("Order_Number")
rcRecordSet.close
Conn.close
set rcRecordSet = nothing
set Conn = nothing
模块化框架简介
模块化允许分解组件和/或功能,并将它们重新组合。这种方法是一种设计技术,强调将自动化的功能单元(AUT)的功能分离成独立的、相互连接的模块,使得每个模块只包含执行所需功能一个方面的所有必要元素。
要实现模块化,需要在两个不同的层面上进行模块化;一个层面是测试层面,另一个层面是脚本层面。为了创建一个模块化框架,我们需要根据其目标将测试层分解成可管理的部分。例如,常见的测试库与功能库是分开的。在测试层面,我们将关键库和资源分解成结构,以使用适当的设计实现自动化目标。
模块化框架有四个不同的部分:
-
脚本层面模块化
-
测试层面模块化
-
资源结构
-
框架设计
让我们以 Flight 应用程序为例;整个功能可以划分为如以下图所示的小独立函数。这需要实现如以下图所示的脚本层面模块化:

小贴士
我们可以省略一些作为自动化一部分的最少使用且不贡献于投资回报率的函数,例如图形、编辑和在 Flight 应用程序中的帮助。
除了将整个功能分解成小而独立的函数外,我们还需要确保其他组件也应该被分解。分解后,整个测试组件看起来如下图所示:

前面的列表包含了最常用的组件,但框架的实现可能需要根据自动化目标和要求拥有更多或更少的组件。以下是对这些组件的描述:
-
功能库:这是一个执行特定任务的脚本集合。通常是一个任务,允许在 AUT 的语句集上执行。
-
测试数据:这些数据存储在
datatable中,或者外部数据源为测试提供输入。 -
日志文件:它们捕获用于查看测试脚本结果的日志消息。
-
主脚本:这些驱动测试流程,并允许与其他组件协调,以确保测试成功运行。
-
错误处理器:这些允许在发生错误时优雅地退出测试,并揭示有关错误的信息。
-
OR:这是包含测试对象的测试的一部分;通常 OR 是一个共享 OR。
-
环境:这是一个组件,用于提供测试级别的环境变量或值,允许配置需要在各种环境中运行的测试。
结构
在测试分解后,资源需要以结构化的方式进行排列,这意味着有一个集中存储这些资源的仓库。管理测试需要文件夹结构或测试管理工具(例如,质量中心)来存储测试资源。我们需要确保测试组件符合指南和结构。结构允许组织资源以实现可移植性和一致性。框架的文件夹结构如下所示。结构可能因项目而异,但实现一致性很重要。

优点
结构有以下优点:
-
促进专业化:结构化设计组件以执行特定任务,并提供从复杂性中抽象出来的功能。
-
资源控制:资源结构简化了对资源的控制,因为它们位于集中位置,并受访问、创建和更新资源的策略管理。
-
更易沟通:资源结构以受控方式明确说明团队成员之间信息流的流程。修改是在集中位置进行的,并由所有其他团队成员使用。
-
更好的性能:每个组件都专门用于执行其任务,并且经过彻底测试以提高性能和可靠性。
提示
总是使用相对路径;不要在脚本中硬编码资源位置。
设计
设计是框架最重要的方面。框架的设计由其关键自动化目标驱动。以下是一个全面但不完整的列表,如果需要,可以添加更多目标:
-
可维护性:它允许分解资源和脚本;这使得维护和调试更容易,并且可以更快、更可靠地解决问题。
-
可读性:这是一个设计良好且功能较小的函数,它提高了脚本的可读性,并使其更容易理解,同时也增强了它。
提示
注释和脚本/函数头对于提高可读性和理解性非常重要。
-
可扩展性:当创建小型函数并结构化资源时,扩展现有功能变得容易。这使我们能够轻松添加和增强功能、调试和测试。
-
可重用性:允许函数重用的功能使框架更加健壮和可靠。
提示
在我们开始设计框架之前,我们应该考虑可以在测试脚本中跨脚本使用的功能,以增加可重用性。彻底测试这些常用功能,并确保它们具有必要的错误处理能力。
-
简洁的脚本:确保脚本简短,一次执行单一任务;这些脚本应该是适当库或模块的一部分。确保脚本紧密耦合且松散耦合。
高内聚和耦合
耦合指的是代码中可以重用且可以与代码分离但直接是其一部分的部分。而内聚性是衡量一个类/代码中所有职责、数据和方法的相互关联程度。
尤其是我想通过框架的设计和架构实现以下三个具体目标的最小化:
-
将必须一起改变的代码部分尽可能放在一起。
-
允许代码中不相关的事物独立改变(也称为正交性)。
正交性是一个允许将小组件组合以获得有效结果的概念。这简化了读写程序。更正交的设计允许更少的异常、对称和一致性。
-
最小化代码中的重复。
实现模块之间松耦合背后的目标是:
-
使代码更容易阅读
-
通过隐藏复杂性使我们的代码更容易被其他开发者消费
-
将潜在的变化隔离到代码的小区域
-
在完全新的环境中重用代码
减少耦合,增加内聚
我们通常认为高内聚性对于设计框架库如关键设计考虑因素是好事,但为什么?
看看以下代码。我们需要一个连接字符串来连接到数据库,连接字符串和数据库操作代码是紧密耦合的。好吧,这里的问题是什么?现在如果我们想更改 DSN,我们需要为每个 DSN 更改代码:
Set Conn = CreateObject("ADODB.Connection")
Conn.Open("DSN=QT_Flight32")
Set rcRecordSet= Conn.Execute("SELECT order_number from Orders order by order_number desc")
rcRecordSet.MoveFirst
var_order_num = rcRecordSet.fields("Order_Number")
rcRecordSet.close
Conn.close
set rcRecordSet = nothing
set Conn = nothing
让我们重写这段代码,使其耦合度更低,内聚性更高。我已经将代码分为两部分。第一部分是一个返回 DSN 的函数,第二部分使用该 DSN 并操作数据库。现在如果用户想访问另一个数据库,DSN 将不同,用户只需更改参数。之前的代码是耦合的,而下面的代码是内聚的:
Function getDSN(database)
If database = "access"
DSN ="DSN=QT_Flight32"
ELSEIF
…
End Function
Set Conn = CreateObject("ADODB.Connection")
Conn.Open(getDSN("access") )
Set rcRecordSet= Conn.Execute("SELECT order_number from Orders order by order_number desc")
rcRecordSet.MoveFirst
var_order_num = rcRecordSet.fields("Order_Number")
rcRecordSet.close
Conn.close
set rcRecordSet = nothing
set Conn = nothing
在 QTP 的上下文中,还有一个设计考虑因素,那就是我们是否应该使用操作或函数。
从我的个人经验来看,我们应该使用函数。操作具有许多优点,并且在实现任何框架时都应优先考虑。函数允许我们实现目标而不需要功能分解。为了创建框架,需要通用的库;例如,需要 Logger、错误处理程序和配置实用程序来实现以下目标:
通过使用操作或函数将整个流程划分为小块,可以增强其可用性。
设计模块化框架的关键步骤如下:
-
分析应用程序
-
创建设计
-
创建自动化测试库
-
创建测试级别的组件
-
创建脚本级别的函数
-
集成
-
测试它
分析应用程序
分析应用程序将自动化目标定义为预期应用程序定义的函数和操作。分析的关键考虑因素是:
-
应用程序的关键功能是什么,它们之间是如何相互关联的?
-
关键流程是什么?
-
哪个功能使用最少?它会对投资回报率产生影响吗?
-
我们希望通过自动化实现什么目标?
创建设计
创建设计详细描述了所需的功能和操作,包括布局、模块、规则、验证以及模块之间的交互,以及流程图、伪代码和其他文档。
实现模块化的关键是通过对功能进行分解和重新组合模块:
-
分解:用户与应用程序的交互被分解为库,例如功能库(登录、创建订单等)、通用库、OR、测试数据和环境。
-
重新组合:交互的基本元素通过使用多个聚合级别遵循正式的测试计划进行重新组合。将步骤聚合以形成基本步骤的序列,将基本步骤的序列组合以形成场景。将场景聚合以形成测试套件。
在分解和重新组合后,整体模块化框架设计将类似于以下图表:

设置环境
执行以下步骤以设置测试环境:
-
创建结构,这与创建测试基础设施相同。
-
创建资源,包括安装。
-
在测试管理工具中创建文件夹结构或资源。
-
确保版本控制(良好实践)。
-
创建配置文件。
创建对象存储库
通过添加对象(将对象添加到本地存储库或记录自动创建测试对象的测试步骤)来创建 OR。
创建测试级别组件
执行以下步骤以创建测试级别组件:
-
准备测试数据。
-
创建通用函数/库。
-
创建功能库。
-
创建测试流程。
-
通过加载库添加通用组件。
创建脚本级别函数
执行以下步骤以创建脚本级别组件:
-
手动创建步骤。
-
添加所需的编程逻辑。
-
调用通用函数(验证点)。
-
调用
err处理程序。
集成设计元素
将所有组件组合到测试环境中,并确保测试自动化是端到端工作的。
测试框架设计
最后,我们可以执行测试以检查错误、缺陷和互操作性。
报告错误,修复它们,并重新测试。
模块化框架的优势
-
功能分解使我们能够分而治之复杂性。
-
模块化简化了框架的设计、实现和调试。
-
提供标准接口以相互通信,并允许插入和移除新模块。
模块化框架的挑战
创建模块化框架的关键挑战如下:
-
创建通用模块需要更多的技术知识和努力
-
对于非常具体的模块,制作接口的成本很高
-
对于汇编器(集成者)来说,评估不同模块的质量和交互可能很困难
-
组装(集成)模块可能很困难
-
模块设计者的设计创造力可能受到限制,因为他需要符合接口
-
由于过度使用相同模块,产品变化较少
-
总体系统性能可能不是最优的
关键字驱动框架
关键字驱动测试也称为表驱动测试或基于动作的测试。它是一种软件测试方法。
关键字驱动测试使用电子表格以特定格式指定测试用例,通常以表格形式。这些功能是为每个关键字设计的。该关键字存储在表格的行上的列中。例如,在关键字驱动方法中,每个动作都有其对应的功能存储在功能库中。驱动脚本驱动整个流程,获取动作,并调用相应的功能。
关键字驱动测试方法
关键字驱动方法是指将用户与应用程序的交互抽象为动作的形式,并在外部源中维护数据。
分解
用户与应用程序的交互被分解为基本元素(登录、选择航班……)。在关键字驱动方法中,一个关键字代表在 AUT 上执行许多动作或重复执行小动作的业务场景。交互的基本元素被称为步骤。
重组
交互的基本元素被重新组合,以遵循正式的测试计划,使用多个聚合级别。步骤被聚合以形成基本步骤的序列(s),基本步骤的序列被组合以形成序列组。
参考以下截图,展示了使用驱动脚本从其库函数映射动作。用户与应用程序的交互以动作和数据的形式在外部源中抽象表示。
将测试用例与脚本分开。测试用例被保存在脚本之外。这些由驱动脚本获取,并调用关键字功能,如以下截图所示:

一旦找到关键字,就会调用相应的关键字库函数,如以下截图所示:

开发关键字驱动框架首先需要实现模块化;除此之外,我们还需要关键字功能库、测试用例和驱动脚本。关键字驱动框架是一个模块化框架,加上存储在外部源中的测试用例和具有特定功能库的驱动脚本,也称为关键字库。
功能分解是设计关键字驱动框架的重要活动,分解指南用于识别关键字。关键字是可重用的函数,在 AUT 上执行一个或多个关键动作,执行特定任务,并按自己的方式完成。关键字驱动框架的另一个重要方面是测试用例与测试脚本分离。
关键字驱动或测试计划驱动方法
这种方法利用了功能分解的优势,将执行与脚本分离。测试用例定义在包含关键字的电子表格中。每个关键字都有一个相应的函数库,该库在 AUT 上执行操作。
在这种方法中,整个过程都是关键字驱动的,包括功能。关键字控制处理过程。
关键字驱动测试(KDT)是为了简化自动化测试用例的创建,并尽可能使其与手动测试用例相似而创建的。KDT 根据输入到电子表格中的信息“即时”创建 QTP 自动化测试脚本。
测试用例表示将在行和列中。在测试场景电子表格中,每个测试用例将执行一个动作。
注意
在自动化测试中,最低粒度是测试用例步骤。步骤级别是每个动作或验证发生的地方。
根据 KDT,我们需要为每个区域准备数据电子表格,因为功能可能根据不同的区域而有所不同。一些区域对商业团体、单个企业等有特定的覆盖率。在测试脚本中处理这些内容很困难。测试套件准备用于指定需要执行哪些区域/区域,脚本被通用化。脚本基于电子表格驱动,该电子表格将从区域获取 Excel 数据并生成“即时”脚本。
设计关键字驱动框架的关键步骤:
-
分析应用程序。
-
创建设计。
-
创建自动化测试存储库。
-
创建测试级别的组件。
-
创建脚本级别的函数。
-
集成。
-
测试它。
我们已经看到了创建模块化框架的关键步骤。对于关键字驱动框架,方法也是相同的。
让我们了解关键字驱动方法中的自动化存储库。总的来说,它包含与文档、测试套件和创建的测试用例及库相关的数据。
测试用例也被称为测试场景或测试组,其中包含指定执行测试步骤的电子表格。
常用库包含 QTP 库文件和(.vbs,.qfl)文件,这些文件控制整个 KDT 控制流,例如,驱动脚本和库文件(.qfl,.vbs)。常用库可以被视为:
-
效用函数
-
导航函数
-
支持函数
环境库包含用于设置环境的.xml和.qfl文件。
错误库包含用于在执行过程中捕获错误并执行必要操作的文件(.qfl或.vbs文件)。
框架文档包含为框架创建的所有数据,例如,对初始框架的增强或为框架创建的帮助文件。
对象库包含使用 QTP 创建的.tsr对象文件。
以下图显示了各种层和组件如何协同工作以实现整体设计:

关键字驱动方法中的通用流程
关键字驱动方法中的关键步骤及其执行顺序如下:
-
从电子表格中获取提到的关键字。
-
从下一步骤构建参数列表。
-
调用实用函数;实用脚本将执行以下操作:
-
使用从实用脚本接收的输入参数列表调用实用脚本。
-
调用驱动脚本执行特定任务(例如,登录、选择航班等),如果需要,调用用户定义的函数。
-
向测试报告报告测试用例的错误。
-
异常处理脚本。
-
返回到驱动脚本。
-
-
重复 1 到 3 步。
关键字驱动方法的优点
关键字驱动方法提供的关键优点如下所述章节所述。
成本效益
关键字驱动自动化框架降低了测试设计、自动化和执行的成本和时间。关键字是高度可重用的函数,代表在 GUI 上执行的业务场景或操作。这些经过良好设计和测试的函数在一段时间内提供了良好的投资回报。
分离测试用例允许在不修改脚本的情况下执行测试用例。当应用程序的流程发生变化时,只需更改测试用例而不是脚本。
可重用性
关键字、实用工具和函数被构建以实现可重用性。整个框架被划分为相互集成的层。
易于维护
-
关键字驱动方法提供了从复杂性和技术挑战中的抽象;易于维护
-
关键字驱动的框架的健壮性允许适应 GUI 和测试流程的变化
-
允许在不修改脚本、函数和实用工具或进行最小更改的情况下专注于测试用例的开发。
易于执行
关键字驱动方法允许非技术测试人员、业务分析师和 SMEs(主题专家)执行和创建自动化测试用例。
测试用例与脚本分离,并且使用关键字准备测试用例很容易,无需了解它们是如何实现的。
关键挑战
需要设计知识。
新团队成员需要付出努力去理解框架及其设计。良好的文档和知识共享是克服这一问题的必要条件。
混合框架
混合框架允许结合两个框架的优势,并消除它们的弱点。大多数开发出来的框架都属于这一类别,它们使用功能分解,如模块化框架和数据驱动方法。
设计混合框架的关键步骤如下:
-
创建文件夹结构。
-
创建和存储自动化资源。
-
组织和管理资源。
-
集成框架。
-
干运行。
混合框架的优势
混合框架允许利用其他框架的优势,并消除它们的不足,这适合自动化。实际上,大多数测试自动化解决方案都属于这一类别。
关键挑战
虽然它缓解了其他方法的弱点,但它失去了其通用性,并且非常具体于测试自动化解决方案 AUT,这降低了其组件在多个 AUT 之间的可重用性。
业务流程测试
业务流程测试(BPT)方法允许将业务流程划分为更小的可重用组件,这些组件可以在相同的或不同的测试脚本中使用多次;例如,购买产品的业务流程被划分为登录、选择产品、添加到购物车、下订单和登出等组件,这些组件可以在相同或不同的业务流程中重用。其关键优势是它促进了 SMEs、Bas 和自动化工程师的有效工作和协作。有些人称之为框架,但这更像是一种方法而不是框架。BPT 类似于使用 QTP 和 Quality Center 创建测试自动化解决方案的模块化方法。
应用独立框架
应用独立框架是一种特定的关键字驱动测试或表格驱动测试。它识别出独立于 AUT 的关键字,可以直接对 AUT 的组件执行特定操作。关键字驱动框架与应用独立关键字驱动框架之间的关键区别在于库。在应用独立关键字驱动框架中,功能库更为通用或直接作用于 AUT 的通用组件。以下为数据表:
| 窗口 | WinObject | 操作 | 参数 |
|---|---|---|---|
| 计算器 | 按钮 | 点击 | 1 |
| 计算器 | 按钮 | 点击 | + |
| 计算器 | 按钮 | 点击 | 3 |
| 计算器 | 按钮 | 点击 | = |
| 计算器 | 文本 | 验证结果 | 4 |
AUT 的功能在数据表中指定。前一个表允许在计算器窗口上计算一些操作,例如 1 + 3 =,并验证结果。操作说明如下:
-
在计算器窗口中点击按钮(1)。
-
在计算器窗口中点击按钮(+)。
-
在计算器窗口中点击按钮(3)。
-
在计算器窗口中点击按钮(=)。
-
验证计算器中的文本结果。
操作列列出了使用鼠标、键盘或特定功能执行的操作。数据表应映射以生成测试步骤;例如,鼠标点击按钮,按钮通过参数(1)识别。控制名称在WinObject列中给出,而Window列包含应用程序的名称。
在 QTP 中,对象存储库存储测试对象并提供其逻辑名称|给它。我们可以使用这个逻辑名称作为参数来创建脚本;例如,我们可以使用 Excel 存储对象层次结构并包含数据。也就是说,利用代码创建与应用程序无关的框架。以下图表展示了我们如何使用 Excel 实现应用程序无关的实现并将其转换为脚本。所有对象的名称都列在列中;在运行时,它获取对象信息并创建如图所示的脚本:

在前面的图表中,我们可以观察到脚本在运行时创建对象,而不是硬编码的脚本。这使应用程序从其他应用程序中独立出来。
应用程序无关框架的优势
应用程序无关的关键字驱动框架继承了关键字驱动框架的所有优点,除了允许我们在不同的应用程序上工作而不需要太多更改之外。
应用程序无关框架的关键挑战
创建与应用程序无关的框架需要更多的专业知识来处理创建通用库的复杂性。
与应用程序无关的关键字驱动方法通常是为特定技术设计的,而不是为多种技术设计的。
QTP 提供的最基本框架是回放机制和创建测试步骤的简单步骤。这些步骤被放入可重用函数中,成为模块化和关键字驱动框架中的功能库。参数化步骤并允许其迭代成为数据驱动方法。参考以下图表,展示了我们在开发一个框架时执行的步骤,该框架成为开发下一个框架的基础,例如,记录和回放成为数据驱动框架的基础。一个框架成为下一个框架的基础或部分基础。参考以下图表,展示它们之间的关系:

摘要
本章描述了构建框架及其组件的各种概念和方法,以及一种结构,使我们能够保持资源均匀可访问。这有助于实现自动化目标并降低测试自动化套件的维护成本。
在下一章中,我们将讨论调试脚本、自定义日志部署以及维护框架的各种方法。
第五章:部署和维护框架
在上一章中,我们学习了如何设计和创建测试框架。在部署框架时的关键考虑因素是可移植性和底层环境的配置。调试是一个重要的预部署活动。在本章中,我们将讨论以下内容:
-
QTP 中的脚本调试技术
-
预部署审查清单
-
自定义日志和过滤日志消息
-
部署框架
-
维护框架
预部署
一旦框架测试完成并且已经提出错误,我们将开始调试。此过程试图通过查看以下内容来找出框架中出了什么问题:
-
失败的原因
-
失败的地方
-
如何修复错误
在设计阶段计划调试,并通过开发自定义和错误日志来实现。提供过滤、启用和禁用日志和功能的机制。这有助于在框架设计的开发和维护阶段调试脚本。QTP 为调试脚本、动作和功能库提供了各种选项。
使用 QTP 进行调试
QTP 为调试属于功能库或动作的脚本提供了各种方法。要调试脚本,从脚本或动作的开始执行到某个步骤,或从某个步骤执行到脚本或动作的结束。以下部分描述了 QTP 提供的各种调试脚本的技术。在开始调试脚本之前,请确保应用程序已打开相关位置。
运行到步骤
当点击此选项时,它将从脚本或动作的开始(仅限专家视图)运行测试到测试或动作的当前位置,并在特定步骤停止执行。要从开始运行测试,导航到资源 | 运行到步骤或按Ctrl + F10。
从步骤调试
要从步骤进行调试,而不是从脚本或动作的开始,使用从步骤调试选项;它允许您从测试或动作的特定步骤进行调试。要从特定步骤进行调试,导航到资源 | 从步骤调试。
从步骤运行
指示 QTP 从特定步骤而不是从脚本的开始或动作的开始运行动作。为此,导航到资源 | 从步骤运行。
在专家视图中,从步骤运行选项将从所选脚本运行到动作的结束(或直到达到断点)。在此模式下使用从步骤运行选项将忽略任何迭代。然而,如果动作包含嵌套动作,QTP 将运行嵌套动作,直到达到嵌套动作定义的迭代次数。
从动作运行
此选项将从脚本的开始运行测试到所选动作的开始,然后暂停运行会话。导航到测试流程面板,右键单击从动作运行。
从动作调试
指示 QTP 从所选动作的开始处开始调试会话并暂停。导航到测试流程面板,然后右键单击从动作开始调试。
运行到动作
指示 QTP 从所选动作的开始处开始运行会话。导航到测试流程面板,然后右键单击运行到动作。
调试函数库
创建框架需要创建单独的函数库。为了更好的维护,调试函数库的步骤如下:
-
将函数库与一个测试关联起来。
-
在你的测试中,插入对函数库中定义的至少一个函数的调用。
-
运行测试,挂起运行会话,并调试函数库。
小贴士
在调试会话期间,所有文档都是只读的,不能编辑。要在调试会话期间编辑文档,我们必须停止调试会话。
当测试脚本使用
ExecuteFile语句时,执行标记可能无法正确显示。
部署前的检查清单审查
在部署之前,确保我们审查以下点(存在于脚本中或已妥善处理)以降低框架的维护成本:
-
测试应该始终有一个已知的起点。
-
应始终以相同的起点结束。
测试应该从特定点开始,并确保整个基础设施已准备好执行。如果脚本通过启动 AUT 并在执行结束时关闭应用程序来开始其执行,则下一次迭代或测试将从打开应用程序的起点开始。
-
测试应该清理资源:例如,关闭 MS Excel、关闭文件、关闭测试等。
-
配置值而不是硬编码;使用代码片段中显示的环境变量,或使用字典对象:
<Environment> <Variable> <Name>AppPath</Name> <Value>C:\Program Files\HP\QuickTest Professional\samples\flight\app\flight4a.exe</Value> </Variable> <Variable> <Name>ErrFileExtn</Name> <Value>.bmp</Value> </Variable> </Environment> -
适当的注释和脚本头部
标头允许我们阅读关于函数或脚本的简要描述,如下所示。这有助于使脚本和函数易于阅读和维护:
'************************************************** 'Author 'Description 'Date Creation 'Parameters in out 'Change History 'Changed By Date Description '*************************************************** -
可读性和适当的文档。
-
脚本应该是可维护的和易于修改的
脚本和函数头部提高了可读性,并允许轻松修改代码,因为它揭示了关键信息并减少了维护时间。
-
错误处理和错误快照
确保脚本包含使用自定义库、
CaptureBitmap方法或桌面实用程序的CaptureBitmap来捕获快照的代码。 -
如果发生错误,测试应该揭示最大信息。
错误信息应该是清晰和简洁的。
-
日志工具
日志工具是必须的,以提供信息和错误日志。
-
代码应该有适当的同步
确保代码能够通过使用
wait、wait属性、exist、enable和sync来处理同步问题。 -
优雅退出
确保代码能够适当地使用
ExitFunction、ExitFor、ExitTest和ExitAction实现优雅退出。
自定义日志
所有的这些技术都对测试脚本有用,但当我们设计框架时,必须有某些抽象和一系列层来达到实际错误点。自定义日志揭示了错误条件发生的方式和位置。良好的日志机制会显示相关的消息和错误的快照。自定义日志应提供以下内容:
-
启用日志记录
-
禁用日志记录
-
过滤日志
启用日志记录
调试的最简单方法是使用print或MsgBox语句。Print语句在 QTP 日志窗口中显示消息,而MsgBox显示消息框,用户需要明确点击确定。通常不推荐使用MsgBox选项,因为它需要人工干预,但在某些情况下它有助于快速解决问题。
框架的调试版本允许我们打印或显示消息以揭示查找问题所需的信息。QTP 还提供了Reporter对象,可以将消息报告到运行结果窗口。除了print和MsgBox语句外,日志记录是调试的重要工具。以下示例演示了如何启用或禁用日志记录:
-
使用
Reporter对象的Filter属性和rfEnableAll选项,通过Reporter对象显示所有消息 -
使用环境中的
Debug变量将日志消息ON -
使用
MsgBox语句在窗口中显示消息 -
使用
print语句在 QTP 的打印日志中打印值Public Function ActLogin (ldata) 'Author 'Description 'Create Date 'Set the environment variable as rfEnableAll or 0 Reporter.Filter = Environment("DebugOption") ' SyncPage "LoginPage","LoginPage" userdata = Split(ldata,";") name = Mid(userdata(0), InStr(userdata(0),"=") + 1 ) print name password =Mid(userdata(1), Instr(userdata(1),"=") + 1 ) print password Browser("LoginPage").Page("LoginPage").WebEdit("userName").Set name Browser("LoginPage").Page("LoginPage").WebEdit("password").Set password Browser("LoginPage").Page("LoginPage").Image("Sign-In").Click If Environment("Debug") = ON Reporter.ReportEvent micPass ,"Login", "Pass" WriteToLog logfilepath, "Pass","Login","username "& username & and password"& password Else End Function
禁用日志
禁用日志消息与启用消息正好相反:
-
使用
Reporter对象的Filter属性和rfDisableAll选项显示所有消息 -
使用环境中的
Debug变量将日志消息OFF -
使用
MsgBox语句进行注释 -
使用
print语句进行注释
过滤日志
当测试步骤执行后,日志消息会显示以下状态之一:
-
错误
-
警告
-
失败
-
完成或信息
在某些情况下,致命也是日志消息类型的分类之一。
QTP 的Reporter对象允许我们使用ReportEvent方法显示四种类型的消息。ReportEvent的语法如下所示:
Reporter.ReportEvent EventStatus, ReportStepName, Details [, ImageFilePath]
ReportEvent方法将事件报告到运行结果窗口。此方法允许我们通知用户各种事件。
以下为运行结果窗口的状态:
| 事件状态 | 操作 |
|---|---|
0或micPass |
这会将通过的消息报告到运行结果窗口 |
1或micFail |
这会将失败的消息报告到运行结果窗口 |
2或micDone |
这会在运行结果窗口中报告步骤的完成 |
3或micWarning |
这会将警告消息发送到运行结果窗口 |
以下是一个使用ReportEvent方法的示例:
Reporter.ReportEvent micDone, "Test Step1", "Step Done..."
Reporter.ReportEvent micPass,"Test Step3", "Step Pass"
Reporter.ReportEvent micWarning, "Test Step4", "Step Warning"
Reporter.ReportEvent micFail,"Test Step2", "Step Fail"
一旦执行了ReportEvent方法,结果将在运行结果窗口中显示。以下截图显示了图标以及表示可能结果的提示信息:

以下表格列出了Reporter对象中的Filter选项:
| 事件状态 | 操作 |
|---|---|
0 或 rfEnableAll |
将所有事件报告到运行结果窗口 |
1 或 rfEnableErrorsAndWarnings |
向运行结果窗口报告警告和失败状态 |
2 或 rfEnableErrorsOnly |
向运行结果窗口报告失败状态 |
3 或 rfDisableAll |
不向运行结果窗口报告任何状态 |
测试版本与调试版本的区别
在框架测试自动化中,我们编写不会在最终程序中发布的调试支持代码(调试代码)。调试代码确保代码在某个点上正确,或者具有正确的值。调试代码也可以进行注释和取消注释。这可能会很耗时,因此我们更喜欢开启/关闭调试。调试代码在测试版本中不执行,但如果我们需要调试代码,我们可以启用调试代码。这变成了调试版本。以下示例代码显示了我们可以如何启用和禁用日志记录:
Function WritetoLog ( Err_number, Err_description, custom_message)
If environment("Debug") = ON then
Const ForReading=1 , ForAppending=8, ForWriting =2
Dim FilesysObj, logfile,logfilepath
logfilepath = Environment("LogFile")
Set FilesysObj = CreateObject("Scripting.FileSystemObject")
Set logfile = FilesysObj.OpenTextFile(logfilepath &"\log.txt",ForAppending , true)
logfile.WriteLine(now() &" " &Err_number & " "& Err_description& " "& custom_message)
logfile.close()
else
endif
End Function
部署
在测试自动化框架完成并测试后,需要将其发布给自动化工程师、领域专家或甚至业务用户。发布活动从完成后的开发流程中继而来。它包括所有为组装系统做准备并将系统用于使用的操作。因此,它必须确定操作所需的资源并收集信息以执行部署过程的后续活动。部署是在发布之后开始的过程。在发布过程中,以下工件将被交付,但可能根据项目的需求而有所不同:
-
发布说明
-
文档映射(可追溯性矩阵)
-
设计/架构文档
-
配置文件
-
部署指南
-
用户指南
部署是一系列使脚本(框架)可供使用的活动。在部署过程中,确保安装了 QTP 所需的补丁和插件。确保所有必需的参数都已配置。部署后,测试自动化存储库将在本地驱动器的文件夹或测试管理工具中创建。
维护
维护包括错误纠正、功能增强、删除过时功能以及优化。这是一个评估、控制和进行修改的过程,导致代码、GUI 和应用程序流程以及自动化脚本的更改。在典型的软件项目生命周期中,维护导致增强。维护的常见观念是它仅涉及修复缺陷。所有维护活动都可以分为以下四个类别:
-
适应性:这修改了系统以应对环境或 AUT 的变化。
-
完善性:这实现了新的或更改的用户需求,这些需求涉及功能增强。
-
纠正性:这涉及诊断和修复错误,可能是用户发现的错误。
-
预防性:这增加了软件的可维护性或可靠性,以防止未来出现问题。
随着自动测试(AUT)随时间更新,以下之一或多个将保持最新:
-
测试对象:当发布新版本或补丁时,可能需要更改测试对象、它们的属性,以及添加或删除测试对象。
-
OR 中的参数:可能需要更改反映 AUT 变化的 OR 参数。随着对象属性可能发生变化,更新对象描述;这可以通过以下两种方式完成:
-
手动更改对象属性
-
在更新运行模式或维护运行模式下运行测试
-
这两种模式将在以下部分中解释。
我们可以删除、更改或添加测试对象的新版本;这导致测试对象的删除或添加。测试对象被添加或删除,并随着更改重新分配到 OR 中。
脚本/库维护
随着流程的变化,功能性和脚本和库的修改需要更新。在设计框架时,考虑脚本和功能库应该如何更改。在设计阶段,确保设计足够健壮,足以适应最小或无变化。
自动化测试库维护
为了维护框架,我们需要定期清理过时的资源或文档,例如日志文件、结果文件夹和测试数据。
QTP 提供了两种维护脚本的方法。这些将在以下部分中解释。
维护运行模式
当脚本在维护运行模式下运行且对象发生变化时,它会提供更新属性和步骤或保持原始对象和步骤不变的选择。如果 QTP 无法识别测试对象,它会要求用户在 AUT 中指向对象,然后提供更新属性或保持原始对象或步骤的选项。如果更改的检查点值未更新,它们将在不匹配的情况下失败。
更新运行模式
更新运行模式允许我们执行以下操作:
-
更新测试对象描述
-
更新检查点和输出值
-
更新活动屏幕图像和值
决定需要更新什么,并选择前面列表中所示选项。如果 QTP 无法识别对象,它将抛出错误。如果对象已更改,它将更新对象而不会通知用户。
增强
增强过程始于分析变更对脚本的影响。增强测试,调试它,然后发布。
增强过程中的关键步骤如下所示:
-
理解变更及其影响
-
修改脚本并对其进行文档化
-
测试
-
调试并修复错误
-
发布
总体目标是实现低维护成本。维护阶段的问题既包括管理问题也包括技术问题。测试自动化面临各种管理问题,例如估算成本、改变客户优先级和人员配置,而技术问题的例子包括理解有限、影响分析和测试。该框架由于其测试自动化存储库结构和添加、删除和修改脚本和库的标准方式,允许低维护成本。
摘要
本章重点介绍了维护框架所需的技术。调试是快速识别和修复问题的关键技术。下一章将讨论使用 JavaScript,它允许与网页中的 DOM 进行交互,并使用 XPath 创建脚本。
第六章. Web 应用程序中的基于 DOM 和 XPath 的框架
对于 Web 应用程序自动化,QTP 允许我们使用文档对象模型(DOM)和执行 JavaScript。QTP 还使用XPath查找元素。在本章中,我们将学习关于 DOM、基本 JavaScript 和 XPath 术语。我们还将通过示例学习如何使用 XPath 查找元素并在创建脚本中使用它们。QTP 允许在脚本中执行 JavaScript 代码。JavaScript 可以使用 HTML DOM 查找元素、更改 HTML 内容、属性、样式以及删除 HTML 元素。
文档对象模型
文档对象模型(DOM)允许将 HTML 文档表示为树结构,同时也允许动态访问和更新 HTML 文档的内容、结构和样式。
HTML DOM
HTML DOM 定义了 HTML 元素的对象和属性以及访问它们的方法。用简单的话说,HTML DOM 允许以标准方式添加、检索、更改或删除 HTML 元素。在 HTML DOM 中,一切都被视为节点:
-
整个文档是一个名为节点文档的节点
-
每个 HTML 元素都是一个元素节点
-
元素内的文本是一个文本节点
-
节点中的每个属性都是一个属性节点
-
注释是一个注释节点
节点关系 - 父节点、子节点和兄弟节点
HTML 是一种标记语言,它定义了标签;这些标签以以下方式相互关联:
-
每个文档有一个根元素,并且没有父元素。
-
一个节点可以有多个子节点,但只有一个父节点。
-
具有相同父节点的节点被称为兄弟节点。
看以下 HTML 代码片段以了解关系:
<html>
<head>
<title> DOM Example </title>
</head>
<body>
<h1>Chapter 1</h1>
<p>QTP</p>
</body>
</html>
前面脚本中标签之间的关系如下所示:
-
<html>标签是根节点,它没有父节点 -
<html>节点是<head>和<body>标签的父节点,换句话说,<html>节点有两个子节点:<head>和<body> -
QTP 文本节点的父节点是
<h1>节点 -
<head>节点有一个子节点:<title>节点 -
DOM Example是一个文本节点,其父节点是<title>节点 -
<h1>和<p>节点是<body>的子节点,并且彼此是兄弟节点 -
<head>元素是<html>元素的第一个子节点,而<body>元素是<html>元素的最后一个子节点 -
<h1>元素是<body>元素的第一个子节点,而<p>元素是<body>元素的最后一个子节点
JavaScript 和 DOM
DOM 允许 JavaScript 操作所有 HTML 元素、HTML 属性和 CSS 样式。它还允许响应页面中发生的事件。DOM 允许 JavaScript 执行以下操作:
-
查找 HTML 元素
-
修改 HTML 元素的 CSS(层叠样式表)
-
修改 HTML 元素的文本内容(
innerHTML) -
响应 HTML DOM 事件
-
添加或删除 HTML 元素
查找 HTML 元素
DOM 允许以下方式查找 HTML 元素:
-
通过 ID
-
通过名称
-
通过标签名
-
通过类名
通过 ID 查找 HTML 元素
getElementById方法允许通过 ID 检索元素,例如:
var id = document.getElementById("id1");
此方法将返回一个对象。如果找不到元素,ID 将包含一个 null 值。
通过标签名查找 HTML 元素
getElementsByTagName方法允许通过标签名检索元素,例如:
var y = document.getElementsByTagName("p");
通过名称查找 HTML 元素
使用getElementsByTagName方法通过标签名检索元素,如下例所示。getElementsByName方法允许通过标签名检索元素,例如:
var y = document.getElementsByName("userName");
通过 className 查找 HTML 元素
如下例所示,使用getElementsByClassName方法通过类名检索元素。getElementsByClassName允许通过类名检索元素,例如:
var z = document.getElementsByClassName(names);
注意
使用getElementsByClassName方法查找元素在 IE 5、6、7 和 8 中不起作用。
更改 HTML 内容
更改 HTML 元素的内容非常简单,因为它可以通过更改 HTML 元素的innerHTML属性来实现。使用以下语法:
document.getElementById(elementid).innerHTML= new value
以下示例更改了 HTML 元素的内容:
<html>
<body>
<h1 id="headerid">Heading</h1>
<script>
varelement=document.getElementById("headerid");
element.innerHTML="New Heading";
</script>
</body>
</html>
更改 HTML 属性
如下例所示,使用getElementById方法检索 HTML 元素,并更改具有新值的属性:
document.getElementById(elementid).attribute = NewAttributevalue
以下示例更改了具有新值的属性:
<html>
<body>
<img id="logosmall" alt ="Logo">
<script>
document.getElementById("logosmall").alt="This is logo";
</script>
</body>
</html>
更改 HTML 样式
要更改 HTML 元素的样式,请使用以下代码:
document.getElementById(elementid).style.property= new style
以下示例更改了<p>元素的样式:
<html>
<body>
<p id="pid2">Color!</p>
<script>
document.getElementById("pid2").style.color="red";
</script>
<p>The paragraph above is changed to red.</p>
</body>
</html>
此示例在用户点击按钮时更改具有id="pid1"的 HTML 元素的样式:
<!DOCTYPE html>
<html>
<body>
<h1 id="pid1">My Heading 1</h1>
<button type="button" onclick="document.getElementById('pid1').style.color='red'">ClickMe!</button>
</body>
</html>
响应事件
DOM 允许在事件发生时执行 JavaScript 代码或函数;例如,当用户将鼠标悬停在 HTML 元素上时:
object.onmouseover=function(){SomeJavaScriptCode};
以下是一些 HTML 事件的示例:
在以下示例中,从事件处理器中调用了一个函数:事件处理器允许我们调用 JavaScript 函数,如下所示:
<html>
<head>
<script>
function changetext(id) {id.innerHTML="Text is changed!"; }
</script>
</head>
<body>
<h1 onclick="changetext(this)">Click on this text!</h1>
</body>
</html>
创建新的 HTML 元素
首先创建元素节点,然后将其附加到现有元素:
<div id="div1">
<p id="pid1">This is a paraOne.</p>
<p id="pid2">This is paraTwo.</p>
</div>
<script>
var para=document.createElement("p");
var node=document.createTextNode("This is new Para.");
para.appendChild(node);
var element=document.getElementById("div1");
element.appendChild(para);
</script>
以下代码可以解释如下:
-
它创建了一个新的
<p>元素 -
要向
<p>元素添加文本,首先创建一个文本节点 -
将文本节点附加到
<p>元素 -
它找到现有元素
-
它将新元素附加到现有元素上
移除现有 HTML 元素
在移除子元素之前,了解元素的父元素,然后移除它,例如:
<div id="divid1">
<p id="pid1">This is a paragraph.</p>
<p id="pid2">This is another paragraph.</p>
</div>
<script>
//Find the element with id="divid1":
var parent=document.getElementById("divid1");
//Find the <p> element with id="pid1":
var child=document.getElementById("pid1");
//Remove the child from the parent:
parent.removeChild(child);
</script>
以下 HTML 文档包含一个具有两个子节点(两个<p>元素)的<div>元素:
<div id="div1">
Child: 1 <p id="pid1"> This is a paragraph. </p>
Child: 2 <p id="pid2"> This is another paragraph. </p>
</div>
DOM 要求知道元素及其父元素都需要被移除。它不允许在没有父元素引用的情况下移除子元素。解决方案使用子对象的parentNode属性来获取父元素,然后使用removeChild来移除它:
var childelement = document.getElementById("pid1");
childelement.parentNode.removeChild(childelement);
DOM 和 QTP
QuickTest 对 Web 对象的属性允许我们获取 DOM 对象的引用,并可以在 DOM 对象上执行任何操作。例如,以下代码显示页面上的对象允许通过名称 username 获取元素,即下一步的文本框将值设置为 ashish。
Set Obj =
Browser("Tours").Page("Tours").Object.getElementsByName("userName)
'Get the length of the objects
Print obj.length
'
obj(0).value="ashish"
以下代码片段显示了可以使用 Web 对象的 Object 属性执行的各种操作:
'Retrieve all the link elements in a web page
Set links = Browser ("Mercury Tours").Page("Mercury Tours").Object.links
'Length property provide total number of links
For i =0 to links.length -1
Print links(i).toString() 'Print the value of the links
Next
Get the web edit object and set the focus on it
Set MyWebEdit = Browser("Tours").Page("Tours").WebEdit("username").Object
MyWebEdit.focus
'Retrieve the html element by its name
obj = Browser("Tours").Page("Tours").Object.getElementsByName("userName")
'set the value to the retrieved object
obj.value ="ashish"
'Retrieve the total number of the images in the web pages
set images = Browser("Mercury Tours").Page("Mercury Tours").Object.images
print images.length
'Clicking on the Image
obj = Browser("Tours").Page("Mercury Tours").Object.getElementsByName("login")
obj.click
'Selecting the value from the drop down using selectedIndex method
Browser("Flight").Page("Flight).WebList("pass.0.meal").Object.selectedIndex =1
'Click on the check box
Browser("Flight").Page("Flight").WebCheckBox("ticketLess").Object.click
触发事件
QTP 允许在 Web 对象上触发事件:
Browser("The Fishing Website fishing").Page("The Fishing Website fishing").Link("Link").FireEvent "onmouseover"
以下示例使用 FireEvent 方法触发表单上的 onpropertychange 事件:
Browser("New Page").Page("New Page").WebElement("html tag:=Form").FireEvent "onpropertychange"
QTP 允许执行 JavaScript 代码。有两个 JavaScript 函数允许我们与网页交互。我们可以检索对象并在它们上执行操作,或者我们可以从页面上的元素检索属性:
RunScript 执行作为此函数参数传递的 JavaScript 代码。
以下示例显示了 RunScript 方法如何调用 ImgCount 方法,该方法返回页面中的图像数量:
length = Browser("Mercury Tours").Page("Mercury Tours").RunScript("ImgCount(); function ImageCount() {var list = document.getElementsByTagName('img'); return list.length;}")
print "The total number of images on the page is " & length
RunScriptsFormFile 使用 JavaScript 文件的完整路径来执行它。位置可以是绝对或相对文件系统路径,或者是一个质量中心路径。
以下是一个示例 JavaScript 文件(logo.js):
var myNode = document.getElementById("lga");
myNode.innerHTML = '';
使用以下代码中的 logo.js 文件:
Browser("Browser").Page("page").RunScriptFromFile "c:\logo.js"
'Check that the Web page behaves correctly
If Browser("Browser").Page("page").Image("Image").Exist Then
Reporter.ReportEvent micFail, "Failed to remove logo"
End If
上述示例使用 RunScriptFromFile 方法从网页中删除一个 DOM 元素,并检查在删除 DOM 元素后页面是否仍然表现正确。
使用 XPath
XPath 允许在 HTML 文档中导航和查找元素和属性。XPath 使用路径表达式在 HTML 文档中导航。QTP 允许使用 XPath 创建对象描述,例如:
xpath:=//input[@type='image' and contains(@name,'findFlights')
在下一节中,我们将学习各种 XPath 术语和方法,以使用 XPath 查找对象。
XPath 术语
XPath 使用各种术语来定义元素及其在 HTML 元素之间的关系,以下表格显示了这些术语:
| 原子值 | 原子值是没有子节点或父节点的节点 |
|---|---|
| 祖先 | 一个节点的父节点、父节点的父节点,依此类推 |
| 后代 | 一个节点的子节点、子节点的子节点,依此类推 |
| 父节点 | 每个元素和属性都有一个父节点 |
| 子节点 | 元素节点可以有零个、一个或多个子节点 |
| 同级 | 具有相同父节点的节点 |
选择节点
路径表达式允许在文档中选择节点。以下表格显示了常用的路径表达式:
| 符号 | 含义 |
|---|---|
/(斜杠) |
选择相对于根节点的元素 |
//(双斜杠) |
从当前节点选择文档中的节点,无论其位置如何都匹配选择 |
.(点) |
表示当前节点 |
.. |
表示当前节点的父节点 |
@ |
表示一个属性 |
nodename |
选择所有名为 "nodename" 的节点 |
斜杠 (/) 在开头使用时定义绝对路径;例如,/html/head/title 返回 title 标签。如果在中部使用,它定义祖先和后代关系;例如,//div/table 返回包含表格的 div。
双斜杠 (//) 用于在任意位置查找节点;例如,//table 返回所有表格。如果在中部使用,它定义后代关系;例如,/html//title 返回 title 标签,它是 html 标签的后代。
参考以下表格,查看更多示例及其含义:
| 表达式 | 含义 |
|---|---|
//a |
查找所有锚点标签 |
//a//img |
列出链接内的图像 |
//img/@alt |
显示所有 alt 标签 |
//a/@href |
显示每个链接的 href 属性 |
//a[@*] |
带有任意属性的锚点标签 |
//title/text() 或 /html/head/title/text() |
获取页面的标题 |
//img[@alt] |
列出具有 alt 标签的图像 |
//img[not(@alt)] |
列出没有 alt 标签的图像 |
//*[@id='mainContent'] |
获取具有特定 CSS ID 的元素 |
//div [not(@id="div1")] |
从 XPath 创建数组元素 |
//p/.. |
选择 p(段落)子节点的父元素 |
XXX[@att] |
选择 XXX 的所有具有名为 att 的属性子元素 |
./@* 例如,//script/./@* |
查找当前元素的 所有属性值 |
断言
断言被嵌入在方括号中,用于查找特定节点或包含特定值的节点:
-
//p[@align]: 这允许找到所有具有对齐属性值为中心的标签 -
//img[@alt]: 这允许找到所有包含alt标签的img(图像)标签 -
//table[@border]: 这允许找到所有包含border属性的table标签 -
//table[@border >1]: 这找到边框值大于 1 的表格
使用完整路径检索表格行:
//body/div/table/tbody/tr[1]
获取 //body/div/table/..(table 标签的父节点)的名称
//body/div/table/..[name()]
| 路径表达式 | 结果 |
|---|---|
//div/p[1] |
选择 div 元素的第一个段落元素 |
//div/p [last()] |
选择 div 元素的最后一个段落元素 |
//div/p[last()-1] |
选择 div 元素的第二个最后一个段落元素 |
//div/p[position()<3] |
选择 div 元素的第一个两个段落元素 |
//script[@language] |
选择所有具有名为 language 的属性的脚本元素 |
//script[@language='javascript'] |
选择所有具有名为 language 的属性且值为 JavaScript 的脚本元素 |
//div/p[text()>45.00] |
选择 div 元素的具有文本元素值大于 45.00 的所有段落元素 |
选择未知节点
除了在 XPath 中选择特定节点外,XPath 允许我们使用 *、@ 和 node() 函数选择 HTML 元素的组。
-
*代表元素节点 -
@代表属性 -
node()代表任何节点
之前提到的元素允许选择未知节点;例如:
-
/div/*选择div元素的所有子节点 -
//*选择文档中的所有元素 -
//script[@*]选择包含属性的标题元素
选择多个路径
在 XPath 表达式中使用 联合 | 运算符 允许选择多个路径,如下表所示:
| 路径表达式 | 操作 |
|---|---|
| `//div | /p |
| `//p | //span` |
XPath 中的轴
轴允许定义相对于其当前节点的节点。以下是在 XPath 中的轴列表:
-
自身
-
父节点
-
属性
-
子节点
-
祖先和祖先或自身
-
后代和后代或自身
-
后续和后一个兄弟
-
前一个和前一个兄弟
-
命名空间
使用位置路径定位元素
元素的位置可以用绝对和相对路径两种方式表示。
每一步都是针对当前节点中的节点进行评估。语法看起来如下:
axisname::nodetest[predicate]
轴定义了所选节点与当前节点之间的树形关系。
节点测试允许我们在轴中识别节点。
零个或多个谓词允许进一步细化所选节点集。
看一下以下示例:
//input[ancestor-or-self::*[@name='userName']]
在前面的示例中,ancestor-or-self 是一个轴,::* 是节点测试,[@name='userName'] 是谓词,允许我们搜索所有包含在 input 类型元素 //input[ansector-or-self::*[@name='userName']] 中的 ancestor-or-self 元素。
轴允许查找元素的后代;例如:
//div[descendant::p] 允许我们找到所有具有后代为段落的 div 元素。
descendant::p 轴允许查找元素的后代和祖先,例如,查找按钮的所有祖先或查找所有后代为 table 的 div。
//input[Ancestor::div[@align='center']]
//div[descendant::table]
XPath 函数的使用:
-
//div/text():使用text函数从div标签中检索文本 -
//div/node():使用node函数获取div标签下的所有节点
要获取后代,XPath 函数 start-with 查找以 //a[starts-with(@href,'http://ads')] 开头的值。
查找包含 style 属性的所有标签 //*[@style]。
XPath 中的运算符
XPath 表达式使用运算符来构建要评估的条件。以下为 XPath 运算符列表:
| 运算符类别 | 运算符 | 描述 |
|---|---|---|
| 数学 | +-*DivMOD | 加法减法乘法除法 MOD 模数(除法余数) |
| 等于和比较 | =!=<<=>>= | 等于不等于小于小于等于大于大于等于 |
| 逻辑 | OrAnd | 逻辑或逻辑与 |
| 两个节点集 | | 并集 | 计算两个节点集 |
以下表格显示了使用 XPath 表达式中的运算符的一些示例:
| 表达式 | 操作 |
|---|---|
//input | //div/input/.. |
Input 联合 div 的父级中的 input |
//table[@border>=1] |
获取边框大于 1 的表格 |
//table[@id=3]/td[2]/text()+1 |
从第三行第二列检索文本并将其加 1 |
//tr[@id=1] and //tr[@id=3] |
如果两个表达式都为真,则返回 true |
使用 XPath 在查找兄弟元素时的示例,允许找到与它们的兄弟相关的对象,而不是与它们的位置相关:
<html>
<Body>
<br><br>
<table name="maintable" border="1">
<th>Item</th><th>Quantity</th><th>Price</th><th></th>
<tr id=1 width="600px">
<td> HP LoadRuuner </td>
<td > 01 </td>
<td> $27 </td>
<td> <input type="button" value="AddToCart"> </td>
</tr>
<tr id=2 width="600px">
<td> HP Quality Center </td>
<td> 01 </td>
<td> $29 </td>
<td> <input type="button" value="AddToCart"> </td>
</tr>
<tr id=3 width="600px">
<td > HP QuickTest Professional </td>
<td > 01 </td>
<td> $25 </td>
<td> <input type="button" value="AddToCart"> </td>
</tr>
</table>
</body>
</html>
将代码添加到文件中,并保存为 .html 文件。点击 AddToCart 按钮。
删除以下记录的脚本:
Browser("Browser").Page("Page").WebButton("AddToCart").Click
替换并使用以下脚本:
Browser("Browser").Page("Page").WebButton("xpath:=//td[contains(text(),'HP QuickTest')]/following-sibling::td[3]/input").Click
此前的脚本允许点击按钮(AddToCart),该按钮是 HP QuickTest Professional 文本的兄弟。要点击与 HP Quality Center 文本为兄弟的 AddToCart 按钮,请使用以下代码:
Browser("Browser").Page("Page").WebButton("xpath:=//td[contains(text(),'HP Quality Center')]/following-sibling::td[3]/input").Click
XPath 可以在 QTP 脚本中实现。以下部分解释了 XPath 在网页中的各种用法。XPath 用法的示例包括:
-
在文本框中输入值
-
从下拉列表中选择值
-
点击图片和按钮
-
通过 ID、标签名、名称和属性查找对象
-
允许提取信息进行验证
-
将重复对象作为数组下标处理
使用 XPath 创建框架的关键步骤包括:
-
识别要记录的流程。
-
创建 OR(为每个页面创建 OR 或使用对象描述)。
-
识别唯一标识对象的 XPath。
-
定义允许我们检索元素并定义为常量的 XPath。
-
将它们用作对象描述。
使用 XPath 编写脚本的技巧:
-
使用描述性编程(使用
index属性)处理 XPath 表达式中的重复对象或数组下标 -
XPath 允许使用索引来收集元素
-
使用
GetROProperty获取innerHTML以获取值 -
使用 XPath 作为常量定义对象描述,以便更容易维护,并且只需在一个地方更改,无需在整个脚本中更改
摘要
在本章中,我们学习了各种概念和示例。DOM、JavaScript 和 XPath 的知识对于编写脚本非常有用。XPath 和 DOM 是在 QTP 中用于脚本创建和验证最少使用的概念,但通过方便地从网页中检索数据,这些概念在创建手动检查点时非常有帮助。当需要处理或靠近的元素没有 ID 时,路径是一个真正好的导航网站的方法。下一章将讨论在测试自动化框架设计过程中捕获和分享所学到的经验,并将它们用于未来的参考。
第七章. 捕获经验教训
在前面的章节中,我们学习了 QTP 用于创建脚本和框架组件、设计和维护框架的各种技术。在本章中,我们将专注于捕捉经验教训及其对未来使用的利用,以下是一些相关主题:
-
准备学习经验
-
收集和记录学习经验
-
收集经验教训的最佳实践
-
讨论经验教训
-
存储和共享经验教训文档
准备学习经验
一个允许将经验教训作为流程来捕捉的组织将更高效、更有效地执行从构思到完成的测试自动化项目。确保在测试自动化生命周期中获得的知识应以有效的方式被捕捉,以便于未来的参考。
我们将组织以下领域的经验教训:
-
人员
-
过程
-
框架设计
测试经理和自动化负责人对测试自动化、自动化团队以及组织和改进流程负有责任。在每次会议中,他们应该就以下主题提出一系列问题:
-
相对于定义的测试自动化目标,我们已经取得了哪些成果
-
对于下一版本和未来项目,利用经验教训的最佳方式
讨论应围绕以下三个领域组织:
-
人员: 我们在人员配备和自动化设计方面获得了哪些技能、知识和经验;这些将有助于未来的发布和项目
-
过程: 用于自动化以及未来项目应使用或避免的工具、技术或实践
-
设计: 设计和可重用库如何帮助实现目标,以及如何使它们对未来发布和项目更有用
收集和记录学习经验
我们必须按类别收集和存储信息;以下各节中列出的关键讨论领域是我们将捕捉信息的地方:
关键挑战
每个项目都会有一些挑战。记录这些挑战及其缓解方法将有助于未来的工作。这些挑战可能与人员、工具技术、技能或流程有关。
做得好的地方
当积极的结果被捕捉和记录下来时,它们将成为未来项目的指导方针。
可以改进的地方
当我们捕捉到可以改进的地方时,这表明我们可以如何积极利用这些经验来克服已经面临的挑战——这有助于风险识别和缓解。其中一些甚至可以被选为未来项目的目标。
收集经验教训的最佳实践
自动化团队成员总是将学习的钥匙放在心中;这对个人、项目和组织的最佳利益总是有利的。通过记录这些教训,将这些教训写成文字是很重要的。
早期开始捕捉
我们应该从构思阶段开始捕捉学习,这使我们能够捕捉到大部分学习,而不会因为拖延而丢失信息。
文档和确保可重用性
即使最初没有组织,记录教训也很重要。仅仅捕捉和记录教训是不够的。你需要确保这些教训被保存并可供重用;它们应该易于跨各个团队访问。
讨论教训
经验教训围绕以下主题展开:
-
议程: 安排与关键利益相关者的会议,讨论测试自动化的教训。首先,制定会议议程。
-
项目详情: 在这里,你将介绍项目及其详情,例如使用的技术和工具、应用领域以及团队规模和构成。关键利益相关者的详细信息可以总结如下:
-
客户: 此字段将保存客户的姓名。
-
参与/项目名称: 需要提及相应的项目名称。
-
测试经理: 此字段将保存测试经理的姓名。
-
项目经理: 需要输入项目经理的姓名。
-
-
挑战: 向团队简要介绍面临的关键挑战以及你是如何缓解它们的。鼓励每个团队成员参与并积极表达他们的观察和学习。挑战可能属于以下任何领域,包括技术、流程、人员和技能问题。
-
做得好的地方: 你需要向每个人简要介绍做得好的地方。这对于未来的参考作为最佳实践或可重用资产将很有用。这些资产可以是文档或代码库的形式。这些教训将成为后续项目的关键参考点。
-
可以改进的地方: 提及团队可以做得更好的领域;这些教训对于估计工作量、风险缓解、技能发展和培训以及改进未来项目的所有测试自动化方面非常重要。
存储和分享教训
成熟的组织允许存储项目文档和可重用资产,并为未来的项目提供访问权限。为组织内的其他团队提供适当的文档访问权限很重要。一些组织有一个软件过程工程组(SPEG)。SPEG 组的某些成员在将工件提交到中央存储库之前会审查文档和库。
摘要
传播知识和学习有助于测试自动化个人以及组织的成熟度增长。本章讲述了关于经验教训及其重要性的实践和技巧,所有这些均适用于任何测试自动化工具或实践,包括 QTP。









浙公网安备 33010602011771号