当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行Swap交换。这个是SWAP 交换分区的作用。
系统中交换分区的大小并不取决于物理内存的量,而是取决于系统中内存的负荷,所以在安装系统时要根据具体的业务来设置SWAP的值。其实虚拟内存并不是等到物理内存用尽了才使用的,是否尽量的使用或不使用swap,在内核空间有一个参数控制。
# cat /proc/sys/vm/swappiness 60 |
表示默认的swappiness的值为60。换而言之,当swap空间使用达到60%的时候,开始释放物理内存中的cache/buffers。swappiness=0 的时候表示最大限度使用物理内存,然后才是swap空间;swappiness=100 的时候表示积极的使用swap分区,并且把内存上的数据及时的搬运到swap空间里面。
现在服务器的内存动不动就是上百G,所以我们可以把这个参数值设置的低一些,让操作系统尽可能的使用物理内存,降低系统对swap的使用,从而提高系统的性能。例如
# echo 10 > /proc/sys/vm/swappiness |
或者
# sysctl vm.swappiness=10 vm.swappiness = 10 # cat /proc/sys/vm/swappiness 10 |
这表明修改已经生效。但是如果我们重启了系统,它又会变成60。为了让我们的修改长久有效,可以修改配置文件/etc/sysctl.conf:
# echo 'vm.swappiness=10' >>/etc/sysctl.conf |
为了让它即时生效,可执行:
重新载入配置文件。
目前Red Hat(红帽官方)推荐交换分区的大小应当与系统物理内存的大小保持线性比例关系。不过在小于2GB物理内存的系统中,交换分区大小应该设置为内存大小的两倍,如果内存大小多于2GB,交换分区大小应该是物理内存大小加上2GB。其原因在于,系统中的物理内存越大, 对于内存的负荷可能也越大。但是,如果物理内存大小扩展到数百GB,这样做就没什么意义了。
最近,在Gentoo中编译webkit-gtk-1.10.2-r300,辛辛苦苦编译了几个小时,结果报错:
collect2: ld termiinated with signal 9 [Killed] |
通过Google搜索,发现这是由于编译过程中机器的内存耗尽引起的。这就是说解决问题的办法是增加内存。不过加物理内存是远水,解不了近火。既然Linux中的交换分区也是内存的一部分,于是不妨尝试增加交换分区。 这又让我们想起了红帽官方对于交换分区的建议:Linux系统交换分区最适合的大小是物理内存的1-2倍。可是谁又会在分区的时候记得这些呢?不过由于Linux允许文件系统中存在多个交换分区或者交换分区文件,所以亡羊补牢、为时未晚。如果我们的磁盘空间还尚有空余没有划分,那么我们可以直接利用分区工具再分出一个交换分区。倘若你像我一样,所有空间都已经被划分完了,那么只剩一招了—使用交换分区文件。下面我们主要来说说如何利用交换分区文件扩大分区。
首先,需要制作交换分区文件。考虑到我的老机器已有的物理内存是1G、现有交换分区大小是500M。为了我们的编译过程顺利完成,不妨考虑交换分区文件的大小为1G。为此,执行下述命令:
$ sudo dd if=/dev/zero of=/var/tmp/swap bs=1k count=1024000 |
记录了1024000+0 的读入
记录了1024000+0 的写出
1048576000字节(1.0 GB)已复制,5.07655 秒,207 MB/秒
它将在/var/tmp路径创建一个名为swap、大小为1G的分区文件,该分区文件拥有1024000个扇区(block),每个扇区大小为1K。接着,再把这个分区文件格式化为交换分区格式:
$ sudo mkswap /var/tmp/swap |
随后,将它挂载到文件系统:
$ sudo swapon /var/tmp/swap |
如果想要确认交换分区是否挂载成功,可执行:
$ swapon -s Filename Type Size Used Priority /dev/sda1 partition 511996 16192 ?1 /var/tmp/swap file 1023996 0 ?2 |
从显示结果来看,我们确实看到了文件格式交换分区被加载。如果还想要查看系统内存情况,只需执行:
$ free -m total used free shared buffers cached Mem: 995 935 60 0 6 551 -/+ buffers/cache: 376 618 Swap: 1499 15 1484 |
通过扩大swap区,可以正常将webkit-gtk-1.10.2-r300编译完。实际上,用top跟踪webkit-gtk-1.10.2-r300的编译过程,会发现整个编译过程所需要的内存大概在2G左右。而我们通过增加交换分区的大小,总获得了2.5G左右的内存空间。编译完之后,如果我们不再需要这一块交换分区文件,那么可以先卸载再删除它:
$ sudo swapoff /var/tmp/swap $ sudo rm -rf /var/tmp/swap |
倘若我们仍希望交换分区文件为以后的编译提供便利,那么可以选择保留它。不过在使用它之前必须先挂载它,因为一旦重启,原先的挂载便会失效!若要让我们的交换分区文件随机器启动自动挂载,则可修改/etc/fstab文件,例如作如下设置:
$ cat /etc/fstab | grep -i swap /dev/sda1 none swap sw 0 0 /var/tmp/swap swap swap defaults 0 0 |
摘要:分析了内存泄露的发生原因和特点,研究了传统测试方法在测试内存泄露方面的缺陷;提出了自动化测试方法在测试内存泄露中的应用。用自动化测试技术代替繁重的手工测试;利用自动化测试具有可重复性、一致性、可重用性的特点,进行更多更频繁的测试;利用自动化测试技术可以解决一般工具无法检测的问题.最后,列举了两个实际例子。形象地说明了自动化测试技术在软件测试中的优势。所介绍的方法对于结构复杂的大型应用软件具有非常好的效果。
关键词:内存泄露;自动化测试;用例设计;结果分析;
1、引言
随着电信技术的快速发展,网络管理系统(网管)功能不断增强,使得网管界面变得非常复杂。网管用户界面的一级菜单有上百个,二级和三级菜单有上千个。面对如此复杂的界面系统,传统的手工测试已经很难保证软件的质量。为了提高软件的测试覆盖率,对软件进行充分测试,需要建立更加有效的测试环境。
在网管软件开发中,软件运行的稳定性是衡量软件质量的重要指标。影响软件稳定性的因素有很多,其中内存泄露问题是最严重的。存在内存泄露的软件所带来的后果是不可想象的,因此,作为一个测试人员,如何测试内存泄露是整个测试任务中的重要环节。本文针对网管GUI(图形用户界面)进行内存测试,当测试用例达到几百上千个之后,如果仍然是手工测试,测试效率将异常低下。本文提出自动化测试方法,用自动化测试工具Robot 对软件进行测试,较好的解决了以上这些问题。
2、计算机内存以及自动化测试原理
2.1 内存泄露的测试方法
在内存泄露测试方面,目前比较流行的测试工具是Purify。如果一个软件的代码比较简单,用Purify 测试内存泄露的效果会比较好;Purify 可以对申请内存的地方作标记,以此作为内存是否释放的标准。但是Purify 对于大型复杂的软件并不适用;因为这时候简单的作标记已经无法真正的描述内存的使用情况,必须用其他更好的方法来测试。测试中经常存在这种情况:用Purify检测表明没有内存泄露,但是在实际应用中,用户却发现内存泄露很严重。
一个软件只有经过长时间的使用检验没有问题之后才能证明是可用的,但是测试不可能无限期地进行,为了节省时间,只能采取模拟长时间的测试,即在很短的时间内进行大量的操作,等效于长时间的操作。
针对这种情况,测试人员必须真实的模拟用户操作,通过大量的疲劳操作,才能更好的检测是否存在内存泄露。这种复杂的长时间的操作属于系统测试的范围,系统测试是将通过确认测试的软件,作为整个基于系统的一个元素,与硬件、某些支持软件和人员等其它系统元素结合在一起,在实际运行环境下,对系统进行一系列的组装测试和确认测试。
2.2 自动化测试技术
最近几年,自动化测试技术悄然升温。自动化测试一般用来进行回归测试,也可以对软件进行压力测试;本文讨论的就是压力测试,或者称为极限测试。压力测试,也成为极限测试。大多数测试技术,主要是面向正常的程序功能和性能的测试,而压力测试的目的主要是为非正常情况。进行压力测试的思想是“如何能够把系统折腾到什么程度而又不会出错”。测试者站在破坏者的角度来看问题。
自动化测试可以将繁琐的任务自动化,如重复输入相同的测试输入,可以提高准确性和测试人员的积极性,将测试人员解脱出来转而投入更多精力设计更好的测试用例。并且自动化测试可以达到连续不断的无人值守测试,有效地利用了计算机资源。
3、测试用例的设计以及测试结果的保存
3.1 测试用例的设计
测试用例是进行软件测试的主要手段。一个好的测试用例就是要尽量多的发现软件中隐藏的故障,具体而言就是要尽可能的申请释放内存,以测试内存的增长情况。
要实现测试自动化,首先是测试数据的自动输入;测试数据的自动输入是相对比较容易实现的环节。在脚本中可以设置所要输入的数据组合,从而可以控制脚本运行过程;一般自动化测试工具(比如Robot)都可以记录测试人员的所有手工操作,并把这些操作以测试工具可以认识的脚本的形式保存下来;商用测试工具Robot 所用的脚本语言是SQABasic 语言。因为脚本就是命令的集合,所以测试工具可以执行脚本命令,重复执行测试人员的操作。
测试人员可以修改脚本,以完成指定任务;甚至可以手工编写脚本,以程序的形式编制脚本,这样可以让脚本完成更多的功能。
什么是框架framework?
● 整个或部分系统的可重用设计,表现为一组抽象构件以及构件实例间交互的方法;
● 可被开发者定制的应用骨架。
前者是从应用方面、而后者是从目的方面给出的定义。测试框架也是如此,测试框架出现的最终目的是花少量的资源来完成尽可能多的测试任务,所以测试框架的建立以及框架的重用性方面是最值得测试人员深入探究的地方。
什么是测试框架?
测试框架是一组自动化测试的规范、测试脚本的基础代码,以及测试思想、惯例的集合。
测试框架的好处在于:
● 减少冗余代码、提高代码生产率、提高代码重用性和可维护性。提高开发速度,提升测试代码的执行效率;
● 提高软件代码质量,同时引入重构概念,让代码更干净和富有弹性;
● 提升系统的可信赖度,作为回归测试的一种实现方法支持修复后“再测试”,确保代码的正确性。
自动化测试框架介绍
自动化测试框架一般可以分为上下两个层次,上层是管理整个自动化测试的开发,执行以及维护,在比较庞大的项目中,它体现重要的作用,它可以管理整个自动测试,包括自动化测试用例执行的次序、测试脚本的维护、以及集中管理测试用例、测试报告和测试任务等。下层主要是测试脚本的开发,充分的使用相关的测试工具,构建测试驱动,并完成测试业务逻辑。
测试驱动_A
测试驱动是一个自动化测试框架的核心,其决定整个自动化脚本设计。当前比较流行的测试驱动有数据驱动和关键字驱动。
● 数据驱动
测试驱动引擎从数据源获取测试数据,然后将数据以参数的形式传递给测试脚本,最后通过执行测试脚本,验证测试结果,并将测试结果输出。一般数据源与测试结果存储在数据库、Excel文件、CSV文件等。数据驱动主要优点是:测试脚本与测试数据的分离,当应用功能变更时,只需要修改该功能部分的脚本;执行测试用例的人员不需要了解测试脚本的实现,只关注测试数据表与测试报告表。而且测试脚本的执行是离散的,即非线性的,测试人员可以有选择的执行测试用例。
测试驱动_B
● 关键字驱动
关键字驱动的自动化测试框架是在数据驱动的基础上进行改进,数据源里包含的不只是数据,还有关键字,一个测试用例由一个或若干个关键字组成。每个关键字对应个不同的业务逻辑,例如,登录、注销等。数据表通过关键字,查找映射表,执行相关的脚本。
驱动引擎是对数据表的数据进行分析,根据不同的测试数据或关键字调用相应测试脚本。驱动引擎还需完成一些测试环境初始化、全局参数设置、测试用例是否执行的判断,以及测试报告的处理等。
测试脚本开发_A
● 脚本划分
为了方便以后脚本的维护问题,必须对脚本进行有效的分层,同时,提高了脚本的复用率。
→ 公共类库
公共类库包括所有模块都可能用户的操作方法,其抽象了不同模块同性,比如操作excel表的方法、读写测试报告、驱动引擎等。
→ 模块特定类库
在模块内部将可以为该模块共享使用的方法抽象出来,作为一个公共类。它可以是一个单的逻辑操作,也比较独立。比如客户端登录操作、控制台登录操作、控制台更新操作等。
→ 测试用例脚本
测试用例脚在最上层,它根据测试点进行设计,面向具体的应用。它可直接调用公共类库或模块特定类库的方法,即调单个逻辑操作。它是单个或多个逻辑操作的集合,即一个测试用户脚本。
测试脚本开发_B
● 脚本规范
测试脚本的开发也要遵循编程的规则与标准,应该统一规划,所有开发脚本的人员按照统一的规定进行编码。除了编程本身规范,还考虑测试用例与库函数名的命名。
例如,项目M4.1客户端登录测试用例可命名为:TC_M4.1_client_login;读取excel表的函数可命名为:read_excel。
测试用例
● 测试用例粒度
测试用例的粒度决定了用例模型级的复杂度,也决定了每一个用例内部的复杂度。应该根据每个系统的具体情况来把握各个层次的复杂度,在尽可能保证整个用例模型的易理解性前提下决定用例的大小和数目。用例不能太大,这样一旦出执行测试用例出错,不利于定位问题;但也不能太细化,太小则不方便执行。
● 测试用例与测试套件
一个大型的项目有许功能模块,必然会产生大量的测试用例,怎样才能有效的管理这些测试用例呢?这就需要创建测试套件,通过测试套件将测试某一个模块或功能点的测试用例集合起来,方便运行与管理。例如,只验证“用户管理”模块功能,则只需要执行“用户管理”模块套件即可。
选择适合自动化测试的用例
通常适合自动化测试的用例有:
● 产品型项目
产品型的项目,新版本是在旧版本的基础上进行改进,功能变不大的项目,但项目的新老功能都必须重复的测试。
● 回归测试
回归测试是自动化测试的强项,它能够很好的验证你是否引入了新的缺陷,老的缺陷是否修改过来了。在某种程度上可以把自动化测试工具叫做回归测试工具。
● 机械并频繁的测试
每次需要输入相同、大量的一些数据,并且在一个项目中运行的周期比较长。
有一些交互性比较强,需要人工干预的操作,就不要指望通过自动化测试来完成了。例如,用户使用U-Key登录。
软件自动化框架的发展
基于界面的软件自动化测试框架和工具的发展大致经历了三个阶段
1.简单的录制/回放:由工具录制并记录操作的过程和数据形成脚本,通过回放来重复人工操作的过程。在这种模式下数据和脚本混在一起,几乎一个测试用例对应一个脚本,维护成本很高。而且即使界面的简单变化也需要重新录制,脚本可重复使用的效率低。
2.数据驱动 (data_driven)的自动化测试:从数据文件读取输入数据,通过变量的参数化,将测试数据传入测试脚本,不同的数据文件对应不同的测试用例。在这种模式下数据和脚本分离,脚本的利用率、可维护性大大提高,但受界面变化的影响仍然很大。
3.关键字驱动(keyword_driven)的自动化测试:关键字驱动测试是数据驱动测试的一种改进类型,它将测试逻辑按照关键字进行分解,形成数据文件,关键字对应封装的业务逻辑。 主要关键字包括三类:被操作对象(Item),操作(Operation)和值(value),用面向对象形式可将其表现为 Item.Operation(Value)。关键字驱动的主要思想是:脚本与数据分离、界面元素名与测试内部对象名分离、测试描述与具体实现细节分离。
从上面可以看到,自动化测试框架和脚本的发展是和软件工程思想的发展一脉相承的。软件开发的模式从面向机器、到面向过程、再到面向对象、面向服务,是一个从底层到高层、从具体到抽象、复用的粒度从细到粗的发展过程。而软件开发中的模块化、层次化、松耦合等思想对自动化测试框架的设计都具有借鉴意义。
1、分享
1.1 测试环境搭建
在我们进行性能测试之前,通常需要搭建一个供测试用的环境,使用这个环境来录制脚本,根据在这个环境下执行测试的结果,得出最终的测试结论。
有些时候,测试环境就是生产环境,例如:一个新的项目上线前进行的性能测试,通常就是在未来的生产环境下进行的。在这种情况下,可以排除测试环境与生产环境差异带来影响,测试结果相对比较准确。
反之,如果测试环境与生产环境不是同一环境,这个时候,为了保证测试结果的准确性,需要对生产环境进行调研。在搭建测试环境时,尽量保证搭建的测试环境和生成环境保持一致(环境主体框架相同,服务器硬件配置相近,数据库数据相近等)。
另外,最好输出一个测试环境搭建方案,召集各方参加评审确认。同时,在测试方案、测试报告中,对测试环境进行必要的阐述。
1.2 并发量计算及场景设计
首先,在确定场景及并发量之前,需要对业务进行调研,调研的对象最好是业务部门,也可以通过数据库中心查询数据,进行辅助。
场景选取一般包括:登陆场景、操作频繁的核心业务场景、涉及重要信息(如:资金等)业务场景、有提出明确测试需求的业务场景、组合场景等。
每个场景的并发量,需要根据业务调研的结果进行计算。可以采用并发量计算公式:C=nL / T 进行计算(其中C是平均的并发用户数,n是平均每天访问用户数,L是一天内用户从登录到退出的平均时间(操作平均时间),T是考察时间长度(一天内多长时间有用户使用系统))。
每个场景的思考时间,也可以通过业务调研获得。
另外,也可以采用模拟生产业务场景TPS(每秒通过事务数)的方式,来确定场景。相比上一种方式,模拟生产业务场景TPS,能更加准确模拟生产压力。本次ERP性能测试采用的就是这种方式:首先,通过调研确定业务高峰时段,各核心业务TPS量及产生业务单据量。然后,通过调整组合场景中,各单场景的Vusr(虚拟用户数)和Thinktime(思考时间),使每个场景的TPS接近业务调研所得到的TPS量,每个场景相同时间(即高峰时间段长度)通过事务数接近调研业务单据量,从而确定一个,可以模拟生成环境压力的基准场景。最后,通过成倍增加虚拟用户数,来形成2倍场景、3倍场景等。(注:在ERP性能测试组合场景调试过程中,我们发现:各个单场景TPS会受到其他场景的影响(例如:某一个单场景虚拟用户数增加,其他场景TPS就好跟着变化)。因此,建议大家在确定场景并发量时,如果场景比较复杂,最好采用第一种方式)。
最后,同样需要制定场景设计方案,召集相关部门进行评审。
1.3 测试框架搭建
在环境搭建完成、场景设计方案确定之后,下一步工作就是创建脚本。
创建脚本通常有两种方式:录制和手工编写。前一种方式相对比较容易,只需要使用测试工具,进行相关操作即可生成脚本。后一种则相对比较麻烦,需要搭建一个脚本执行的框架,编写各场景对应的代码。
首先,关于测试框架,简单来说就是一个程序运行的环境。以java语言为例:我们都知道,一个简单的java小程序,它要运行起来,我们先要安装JDK(我们可以把它看成是一组API,也可以说是一些java Class),它提供了编译Java和运行Java程序的环境。同理,我们现在想要编写测试脚本,实现特定的功能,那么首先也需要搭建一个可以让它运行起来的环境。
在搭建环境过程中,需要咨询对生产环境框架非常熟悉的工程师,了解整个环境运行的机制。测试框架搭建完成条件:测试脚本在该框架下运行,可以实现登录应用服务器,执行基本业务操作(可以通过在数据库中,查询生成数据进行验证),登出应用服务器。
具体以ERP性能测试框架为例:通过调研分析得出:
1)测试脚本执行需要使用1.4版本jdk;
2)金蝶client端程序运行,jar包调用先后顺序:sp→path→common→client ;
3)金蝶client端与应用服务器建立连接过程:获取客户端元数据(调用MetaDataLoaderFactory.setClientMetaDataPath()方法)→获取启动模块(调用SystemEntry.instance.setStartMode()方法)→初始化系统(调用SystemEntry.instance.initSystem()方法)→登陆应用(调用SystemEntry.instance.login()方法);
4)金蝶client端登出应用服务器方法SystemEntry.instance.logout()。
根据以上几条,我们编写调试出登陆脚本,然后加入具体的业务代码之后,又顺利开发调试出某个基础资料新增脚本(因为金蝶体系固定,基础资料调试通过,代表其他业务功能也可以调试通过),这样整个框架就基本搭建完成。
具体的测试环境搭建细节,参见“ERP性能测试框架搭建”。
1.4 测试脚本开发/调试
测试框架搭建完成之后,就可以开始脚本的开发调试工作了。
首先,这部分工作需要交给,各个业务模块开发员来完成,因为每个模块的代码,只有负责的开发员最熟悉。
在脚本开发前,需要对开发员进行一个简单的培训,将我们测试的大体背景、目标等告诉他们,同时,可以规定一些脚本编写规范(如关联数据库表,核心业务代码行数等注释,为后期场景执行做准备等)。培训完之后,开发人员先在BOS里面进行开发调试,调试通过后,进行简单调整,然后复制到loadrunner中(Init和end中存放登陆、登出代码,详见“ERP性能测试框架搭建”)即可。
下面,简单讲讲脚本开发细节:
金蝶代码可以分为三种:1、客户端代码;2、服务器端代码;3、共用代码。客户端代码由UI界面发布后生成,通常它的功能是获取界面数据、对数据进行校验,增加界面控件监听(如:监听新增按钮,当其被点击后,调用远程接口,向数据库中新增数据),显示界面等。服务器端代码是实体(金蝶元数据,用于建立UI、Query等跟数据库的交互关系)发布生成的,通常可以在里面进行二次编码,实现具体业务功能,供不同客户端调用。共用代码包括接口类、值对象类、枚举类等一些服务器端、客户端需要共用的代码。
目前,ERP开发主要是进行客户端代码(*UI.java)及服务器端代码* (ControllerBean.java)二次开发,而服务端代码已经部署到服务器上,我们的测试脚本开发只需要编写客户端部分即可。当然,客户端部分可能有很多业务对应的方法,我们不是每个都必须调用,可以根据实际情况进行删选。一般情况,输入校验(insertVerify())、核心业务(新增、修改、删除、查询监听方法)都必须写进脚本。
另外,实际业务数据是通过界面输入,我们脚本开发可以将数据写死,然后进行参数化即可。
1.5 场景调试/执行
脚本开发完成后,进入场景调试执行阶段。
场景调试执行分为:单场景执行、组合场景执行。
首先,我们在单场景执行阶段,需要对脚本进行参数化、添加事务、集合点、检查点、思考时间等操作,注意,如果想要真实模拟生成压力,需要对所有核心字段进行参数化(如出发部门、到达部门、单据编号、操作人等)。
然后,执行组合场景时,需要对各单场景,在组合场景中的执行结果进行验证,需要对数据流进行监控,保证参数化数据量充足;可以通过修改每个单场景的虚拟用户数和思考时间,来调整TPS。
最后,不论是单场景、还是组合场景,执行过程中,都会产生很多的脏数据,每次执行场景后,都需要对这些脏数据进行清理。本次ERP性能测试采用了,一种新的脏数据清理方法:数据库闪回。
数据库闪回,首先,需要对数据库进行设置,开启闪回服务,设置闪回空间大小;然后,可以通过一系列的操作,完成数据库闪回:
1)关闭数据库(srvctl stop database -d erp -o immediate);
2)进入SqlPlus(sqlplus / as sysdba);
3)归档模式启动数据库(startup mount);
4)执行闪回操作(flashback database TO TIMESTAMP to_timestamp('2012-04-12 15:10:00','yyyy-mm-dd hh24:mi:ss'));
5)打开数据库(alter database open resetlogs)
1.6 性能监控分析
在场景执行过程中,可以通过使用性能监控工具,对应用服务器、数据库服务器进行监控,一般使用nmon。事务响应时间、通过率等过程记录可以使用loadrunner进行监控。数据库性能可以使用SQL脚本执行进行监控。
对于一些比较专业的性能指标,比如:本次ERP性能测试需要监控的主实例JVM情况,可以交给数据中心或者开发部门。
性能测试执行过程中,发现环境性能问题后,通常会进行一些调整,这个时候,尽可能将之前执行过的场景重新执行,并进行监控。
关于分析,原则上是需要各个部门共同参与,最好每次举行一个分析会,召集相关人员参加,并对分析结果进行讨论。
1.7 结果报告
在场景执行完成,测试分析结束后,开始进行测试报告编写。测试报告编写,要将重点内容放在最前面,要有具体的结果(目标是什么?结果是怎样?性能是否满足要求?),而不能只是分散的结果统计。
2、展望
2.1 业务调研及场景确定
现在,业务调研还存在问题:1)没有真正调研业务部门,都是通过查询数据库,或者通过各种其他途径推算;2)没有形成一个很好的调研流程及方案;场景方面,并发量、思考时间因为调研不全的等原因,无法准确的确定。这些在后期性能测试过程中,都需要去探索、总结。
2.2 场景监控与分析
目前,场景监控经常出现我们测试一个部门监控,其他部门参与不够的情况。场景结果也没有得到很好的分析。其原因,一方面,是我们的技能水平需要提高,另一方面,是如何有效的将各个部门组织参与进来。这些都是我们未来需要进行研究、提升的地方。
利用脚本停止脚本并重新运行脚本
这里列举一些常见的需要重新停止并重新运行脚本的情况:
当动态加载环境变量后必须停止并重新运行才能被正确加载到测试脚本中
当在测试TE过程中需要运行多个Session,QTP不允许在单次脚本运行中运行多个TE Session,若需在脚本中运行多个Session,那么就需要在每个Session最后停止并从下一个session点继续执行。
此技术通常用于重启QTP并且只对第一次运行有效,当在不需要执行脚本并需要重新运行时停止QTP,通过运行一个异步脚本来控制当QTP一旦进入到非运行模式下就运行它直到脚本结束。
'停止并重运行QTP Sub StopAndReRunQTP(restartFlag) '只在flag没有被使用过时重启 If Setting.Exists(restartFlag) = False then '一旦flag不存在则保留flag在整个QTP Session中 Setting.AddrestartFlag,True '调用异步脚本当QTP停止后控制其继续执行 Call AsyncReRunQTP '测试结果中关闭所有事件 Reporter.Filter = rfDisableAll '当出现错误时立即停止脚本 Setting("OnReplayError") = "Stop" '出现错误停止测试r Err.RaisevbObjectError+ 1,"Stop", "Causing Error for Stopping QTP" End if End Sub Sub AsyncReRunQTP() '运行时创建重运行脚本 Call CreateQTPRunScript() '运行异步脚本 Set wShell = CreateObject("WScript.Shell") wShell.Run"ReRunQTP.vbs" End Sub Public Function CreateQTPRunScript() '创建脚本等待qtp停止并重新运行 Set fso = CreateObject("Scripting.FileSystemObject") setfile = fso.OpenTextFile("ReRunQTP.vbs",2, True) file.WriteLine"Set qtpApp = CreateObject(""QuickTest.Application"")" file.WriteLine"While qtpApp.Test.IsRunning" file.WriteLine"Wend" file.WriteLine"qtpApp.Test.Run ,False" file.close setfile = nothing setfso = nothing End Function |
StopAndReRunQTP函数会检查flag是否存在于Setting中,如果不存在则停止QTP,此处Setting设置持续周期起到了关键作用,如果没有它则无法完成以上所实现的功能。
AsyncReRunQTP函数创建并执行了一个VBScript脚本,而此脚本会在运行时重新运行QTP,重运行脚本如下:
'创建QTP应用对象 Set qtpApp = CreateObject("QuickTest.Application") '等待测试停止 While qtpApp.Test.IsRunning Wend '运行测试 qtpApp.Test.Run ,False |
本书章节节选连载已完。想了解更多内容,请至各大书店或通过网络购买本书。
版权声明:51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像。51testing软件测试网欢迎与业内同行进行有益的合作和交流,如果有任何有关内容方面的合作事宜,请联系我们第二十八章 QTP高级应用
在本章我们将会讨论QTP中各种相对高级的常见问题及解决方案,这里故意把本章留在最后,主要的原因是本章的各种概念在之前的很多章节中已经提到过,我们还会介绍Settings对象在运行时遍历所有的子项,此技术可以用于研究发现QTP的一些文档未公开的隐藏特性。
不同机器的测试脚本同步执行
在一些复杂的测试系统场景下会需要QTP去通过脚本去触发另一个脚本以及需要执行的被测应用,在这类情况下,我们需要通过同步通知方式来使不同种类的应用进行协同工作。
为了解决此类问题,我们需要从QTP脚本运行中获取到过程信息,主要是通过QTP的自动化模型AOM下的Environment对象接口来实现所需要的同步进行协作和控制的脚本执行。以下脚本展示了怎样通过自动化模型AOM获取到本地机和远程机上的环境变量Environment对象:
'获取正在运行QTP的对象引用 Set qtpLocalPC = CreateObject("QuickTest.Application") sRemoteIP = "10.1.1.1" Set qtpRemotePC = CreateObject("QuickTest.Application", sRemoteIP) '获取到环境变量 Set qtpLocalEnv = qtpLocalPC.Test.Environment Set qtpRemoteEnv = qtpRemotePC.Test.Environment '最终可以访问到环境变量 MsgBox qtpLocalEnv("TestDir") MsgBox qtpRemoteEnv("TestDir") |
那么现在就需要等待QTP运行合适的位置时对指定环境变量进行更新,看一下如下QTP脚本:
QTP脚本1
'脚本1Script 1 '创建同步点环境变量 Environment.Value("SyncPoint1") = False Msgbox "Job 1 Completed" '实现任意操作 '<-- 另一个脚本会等待此同步点为True Environment.Value("SyncPoint1") = True Msgbox "Starting Job 2" |
VBScript脚本2
此Vbscript脚本会等待QTP脚本1更新SyncPoint1的状态后才开始执行:
'本地机器IP strCompIP = "127.0.0.1" Set qtpApp = CreateObject("QuickTest.Application", strCompIP) '等待脚本停止 While Not qtpApp.Test.IsRunning Wend '等待同步点SyncPoint环境变量更新为True While qtpApp.Test.Environment("SyncPoint1") <> True Wend MsgBox "Script 1 has passed the sync point." |
在QTP中运行脚本1以及脚本2,脚本2将会等待Job 1 Competed消息后弹出Script1 has passed the sync point消息框。
1、背景
1.1 Web程序中的接口
1.1.1 典型的Web设计架构
web是实现了基于网络通信的浏览器客户端与远程服务器进行交互的应用,通常包括两部分:web服务器和web客户端。web客户端的应用有html,JavaScript,ajax,flash等;服务器端的应用非常丰富,比如java的servlet,jsp,ssh框架,.net的aspx,还包括其他脚本如php,python。
web服务器端的设计架构近年来一直比较流行的是三层架构(3-tier application),通常意义上的三层架构就将业务应用划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。分层的目的在于降低代码见耦合,提高代码架构的可维护性。
总的来说,这三层架构的意义如下:
1)表现层(UI):用户界面,即用户可见的操作界面或者入口。
2)业务逻辑层(BLL):封装具有业务含义的操作函数。
3)数据访问层(DAL):封装对数据库或者其他存储介质的原子性操作。
1.1.2 Web接口的概念
web接口是服务器与客户端交互的方式,即浏览器或者其他客户端工具与web服务UI层交互的协议.常见的有两大类,一是浏览器与服务器交互的HTTP协议的接口,另一类web?service接口如soap,rmi,rpc等协议。
HTTP接口请求方法常用的有GET、POST两种请求类型。具有无连接无状态的特征。HTTP请求例如GET?/images/logo.gif?HTTP/1.1,表示从/images目录下请求logo.gif这个文件。
1.2 WEB接口自动化
1.2.1 Web接口测试
web接口测试即站在web服务程序UI层之上自动化测试的一种手段,是站在用户的角度上测试web服务程序业务逻辑的正确性。测试的重点是围绕web服务暴露的接口检查接口数据的正确性,这个过程是将web服务程序当做黑盒,通过自动化测试技术提高测试执行效率降低人工回归的成本。
1.2.2 什么要做接口测试
下图说明了基于HTTP接口的web应用的整体架构特征,按照这种架构设计开发项目,引发两个问题:
第一、系统级测试一定要等到web服务器程序和浏览器端的程序都开发完毕后才能进行吗?参考以下传统的RD与QA合作进行的项目流程,可以看到,QA在RD提测程序后才能真正进入到测试阶段,那么项目的发布周期自然受到这种串行下来的工作安排影响,是1+1的时间周期。
第二、为了提高效率,公司的团队引入了系统级自动化测试的工具或方案,既然是从用户角度去测试,当然要寄希望于从模拟用户行为代替手工操作来进行测试。比如从浏览器操作的方式去测试,能很直接的覆盖用户的一手操作,但是需要思考的是,浏览器各个版本如ie6,7,8,chrome,firefox等,各自有各自特性,JavaScript在浏览器内表现效果又不尽相同,浏览器在不同windows环境下、不同网络条件下运行的状况又不一样,给QA带来一个难题:如何保证浏览器上的自动化case稳定、高效执行?
我们先分析第一个问题,项目团队需要提高产品发布效率,提前QA测试介入的时间点,我们可以想到有几种方案:
1)QA跟随RD进度,加入到各个层级代码参与单元测试:
假设我们没有引入TDD模式没有引入敏捷,那么常规的解决方式是一批被测函数代码由RD写完之后提交svn,然后QA update代码后先花十几分钟阅读代码再加上对业务需求的理解然后再花费十几分钟写Xunit case,与QA预期结果一致则好,不一致则需要再花时间与RD沟通原因等等。其一QA花费更多时间,要深入到RD的代码逻辑深处;其二对QA?coding能力要求也很高,这取决于公司QA人员的定位,是要求QA更熟悉测试设计而代码能力次之呢,还是QA的整体技术能力都要很高,一般来讲大多数的QA强项在于业务需求的熟悉和测试设计能力,所以这种方式对团队整体人员素质的要求非常高。
2)QA不参与单测,RD依据需求纵向拆分功能点然后迭代提测,QA能提前一定时间介入测试:
对照如下的流程示意图说明这个过程,实际上是传统瀑布模型做了拆分,变为了多个短期的“小瀑布模型”,这样的效果能使得项目周期长的产品,可提前介入测试以提前发现问题。
在这样的迭代流程中,如何合理利用自动化手段来提高测试效率呢?一般来讲迭代周期不会很长,常规性的为3~5天一个周期,做太复杂的自动化投入成本较高。对于web系统来讲,为避免过多的自动化投入得不偿失,需要谨慎的判断web系统的特征适合哪种自动化模式。所以这里特别要关注的就是分层自动化测试:
如上图所述,web系统可以做几种功能测试:单元测试,集成测试,系统测试。大多数的产品QA不会太多介入单元测试,集中在集成测试和系统测试。结合上面提到的迭代排期,其实在一般项目中上层UI的开发往往比较滞后,赶工的结果也是提测质量不高。所以可推荐的一种模式是迭代周期内按照UI接口划分功能点做排期,UI的开发可以放在UI接口稳定之后提测。所以迭代周期内,面向UI接口的自动化就是一个将测试前置,并且积累自动化case以待回归时代替手工操作的大好机会。
就着上面这个结论,再分析一下本节开头抛出的第二个问题:“系统级自动化测试的稳定性与可靠性”,先提出几个观点如下:
1)有一些测试点,从系统级角度做自动化的性价比不高:
第一:目前技术手段上还不具备低成本的实现手段的,比如flash、js实现的一些效果、不规范HTML标签、对浏览器运行版本环境考虑不周等引发的问题。导致开发成本高,运行的稳定性较低。
第二:UI实现逻辑比较薄,比如只是查询DB一个字段然后显示在页面,把重点放在后端逻辑检查上性价比更高。
2)系统级测试和集成测试的关注点不同:系统级测试关注的是用户从UI直接操作所能见到的结果,而集成测试关注的是UI接口数据的准确性。比如报表功能,页面上看到的就是一个表格,而对UI接口来讲需要覆盖N种参数组合。
上面两点说的是系统级测试和集成测试的区别之处,在自动化实施过程中,推荐分层的测试思路,既能够细化测试也能综合衡量自动化的投入成本,总的来讲就是以下几点:
1)传统瀑布项目,持续周期长,通过迭代模式可提前介入测试,而迭代周期内系统级功能可能不具备可测性,但是接口可以具备可测性。
2)基于UI的自动化有利有弊,需要结合系统特征综合考虑分层测试的必要,分层后各有测试的侧重点,比如UI自动化重点关注UI的操作流程和显示,集成测试更关注UI接口的参数等价类覆盖和数据正确性。
1.2.3 接口可测性分析
接口显而易见要比UI简单的都,只需要知道协议和参数即可完成一次请求,从自动化测试实施难易程度来看,有以下几个特征:
1)驱动执行接口的自动化成本不高:HTTP,RPC,SOAP,RMI等各类都可以依据相应的协议封装一个client作为接口请求的执行器。
2)整个自动化测试中综合性价比高:接口测试还是属于黑盒范畴,所以比单元测试难度要低;而相比UI自动化稳定性可靠性更高。
2、接口测试工具选型
2.1 常见测试工具
2.1.1 JUnit
JUnit作为单元测试框架常被用作白盒测试,框架具备的一些优良特征有:
1)提供丰富API支持多种验证结果正确性的逻辑
2)通过参数化、@before、@after等特性,支持用例代码可复用
3)suite的模式支持case的批量运行
4)有展现良好的报表
5)与eclipse ide集成,使用方便
2.1.2 HttpClient
HttpClient是一个功能丰富支持HTTP协议的客户端编程工具包,具备以下主要功能:
1)封装实现了所有HTTP的方法,如GET,POST,PUT,HEAD
2)支持redirect,会话保持
3)支持文件上传
2.1.3 HttpUnit
HttpUnit是一个HTTP请求的测试辅助工具,能处理web测试的需求。通过模拟浏览器的行为,处理HTTP请求、会话保持、重定向以及对HTTP?response做DOM解析。
相比于HttpClient,不同之处在于:
1)HttpUnit能对HTTP返回的结果页进行解析,比如DOM元素定位
2)HttpUnit能自己启动一个servlet来运行被测服务
2.1.4 HtmlUnit
HtmlUnit相比HttpUnit功能更加强大,就像一个浏览器,HtmlUnit是Junit的扩展测试框架之一,该框架模拟浏览器的行为,开发者可以使用其提供的API对页面的元素进行操作。HtmlUnit支持HTTP,HTTPS,COOKIE,表单的POST和GET方法,能够对HTML文档进行包装,页面的各种元素都可以被当作对象进行调用,对JavaScript的支持也比较好。
2.1.5 JWebUnit
JWebUnit以HttpUnit和JUnit为基础的一个web测试工具。可以用来验证链接跳转、表单输入和提交、表格内容以及其他?Web?应用程序特性的正确性。相比于HtmlUnit,JWebUnit封装的更友好,编写case也会更加简单。
微软Windows应用编程接口(API)为开发Windows应用程序提供了很多构建好的模块。它提供各种操作方法,比如获取鼠标坐标,窗口句柄,颜色等。QTP支持调用动态链接库内定义的这些方法,但是由于VBScript的限制,只有有限的一部分API可以在QTP中使用。
本章使用的API的更多细节和信息可以从MSDN或者Visual Studio的API Viewer工具查询获得。
Extern对象
QTP提供一个Extern功能对象用来声明和调用API。
语法
Extern.Declare (RetType, MethodName, LibName, Alias [, ArgType(s)]) |
更多细节可参考QTP用户手册。
VB API定义语法
Private Declare Function GetForegroundWindow Lib "user32.dll" () As Long |
对以上API,我们需要使用QTP的Declare方法确定使用的合适参数:
RetType = micLong(函数返回类型)
MethodName = "GetForegroudWindow" (我们可以使用任何其他名字,但是比较好的做法是使用实际API的名字)
LibName = "user32.dll" (如果不是使用Windows系统自带的DLL,那么文件名必须使用绝对路径,例如"C:\MyApp\Lib\mylib.dll")
Alias = "" 或者"GetForegroudWindow"(如果MethodName跟Alias相同,则Alias可以为空值。
ArgType(s) = 本例中不需要传入参数)。
QTP API定义
Extern.Declare micLong,"GetForegroundWindow","user32.dll","GetForegroundWindow" |
以下用一些用例来演示使用API解决通常遇到的问题。
问题 17-1.如何判断当前桌面最上面的为浏览器窗口
'声明GetForeGroundWindow API extern.Declare micLong,"GetForegroundWindow","user32.dll","GetForegroundWindow"
'获取最前面窗口的句柄 hwnd = extern.GetForegroundWindow()
'判断是否有包含此句柄的浏览器窗口 isBrowser = Browser("hwnd:=" &hwnd).Exist() If isBrowser then Msgbox "The top most window is a browser" End if |
问题 17-2.如何获得Windows的环境变量 (注意不是QTP环境变量)
'变量声明 Dim s_EnvValue
'声明 API "GetEnvironmentVariable" Extern.Declare micLong,"GetEnvironmentVariable","kernel32.dll","GetEnvironmentVariableA", _ micString,micString+micByRef,micLong
'获取全局变量 "TEMP" 值 Extern.GetEnvironmentVariable "TEMP",s_EnvValue,255 '会得到临时目录路径 MsgBoxs_EnvValue |
问题 17-3.如何使用Windwos API选中Listbox里的选项(item)
' 声明API Extern.Declare micLong,"SendMessage","user32.dll","SendMessageA",micLong,micLong,micLong,micLong
' 设置Listbox选项item的消息 Const LB_SETSEL = &H185
'方法:根据index选中复选框 Function CheckListBox(hwnd, index) extern.SendMessagehwnd, LB_SETSEL, True, index end function
'方法:根据index取消选中复选框 Function UnCheckListBox(hwnd, index) extern.SendMessagehwnd, LB_SETSEL, False, index end function |
问题 17-4.如何取到一个文本框的背景色 (当验证必填项跟可选项底色不同时可用到)
'声明需要的 API Extern.Declare micLong,"GetPixel","gdi32","GetPixel",micLong,micLong,micLong Extern.Declare micLong,"GetWindowDC","user32","GetWindowDC",micLong Extern.Declare micLong,"ReleaseDC","user32","ReleaseDC",micLong,micLong Extern.Declare micLong,"GetDC","user32","GetDC",micLong Extern.Declare micLong,"SetForegroundWindow","user32","SetForegroundWindow",micLong
Dim hDCSource Dim hWndSource Dim backColor '取得控件的句柄 hWndSource = Window("Window").WinEdit("MandatoryField1").GetROProperty("hwnd")
'将窗口置于最上面,因为GetPixel方法只能针对可见像素使用 extern.SetForegroundWindowhWndSource
'取得设备上下文句柄 hDCSource = Clng(Extern.GetDC(hWndSource))
'取得相关控件的像素(1,1)点的背景色 backColor = Clng(Extern.GetPixel(hDCSource, Clng(1),Clng(1))) MsgBoxbackColor
'释放设备上下文句柄 Extern.ReleaseDChWndSource, hDCSource |
问题 17-5.如何使用Windows API模拟键盘操作
'声明API:键盘事件keybd_event extern.Declare micVoid,"keybd_event","user32" ,"keybd_event", _ micbyte,micbyte,miclong,miclon '声明API:虚拟按键码映射MapVirtualKey extern.Declare micLong,"MapVirtualKey","user32","MapVirtualKeyA", _ micLong, micLong
Const KEYEVENTF_EXTENDEDKEY = &H1 Const KEYEVENTF_KEYUP = &H2 Const KEYEVENTF_KEYDOWN = &H0
Sub KeyDown(KeyAscii) keyCode = extern.MapVirtualKey(KeyAscii, 0) '触发按键按下事件 extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYDOWN, 0 End Sub
Sub KeyUp(KeyAscii) keyCode = extern.MapVirtualKey(KeyAscii, 0) '触发按键抬起事件 extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYUP, 0 End Sub
Sub KeyPress(KeyAscii) KeyDownKeyAscii KeyUpKeyAscii End Sub |
对“计算器”使用以上代码
'声明键值常量 Const vbKey1 = 49 Const vbKey2 = 50 ConstvbKeyAdd = 107 ConstvbKeyReturn = 13
SystemUtil.Run"calc.exe" Window("title:=Calculator").Activate Call KeyPress(vbKey1) Call KeyPress(vbKeyAdd) Call KeyPress(vbKey2) Call KeyPress(vbKeyReturn) |
使用以上代码模拟CTRL+ALT+S
'声明键值常量 ConstvbKeyControl = 17 ConstvbKeyAlt = 18 ConstvbKeyS = 83
Call KeyDown(vbKeyControl) Call KeyDown(vbKeyAlt) Call KeyDown(vbKeyS) Call KeyUp(vbKeyS) Call KeyUp(vbKeyAlt) Call KeyUp(vbKeyControl) |
问题 17-4.如何取到一个文本框的背景色 (当验证必填项跟可选项底色不同时可用到)
'声明需要的 API Extern.Declare micLong,"GetPixel","gdi32","GetPixel",micLong,micLong,micLong Extern.Declare micLong,"GetWindowDC","user32","GetWindowDC",micLong Extern.Declare micLong,"ReleaseDC","user32","ReleaseDC",micLong,micLong Extern.Declare micLong,"GetDC","user32","GetDC",micLong Extern.Declare micLong,"SetForegroundWindow","user32","SetForegroundWindow",micLong
Dim hDCSource Dim hWndSource Dim backColor '取得控件的句柄 hWndSource = Window("Window").WinEdit("MandatoryField1").GetROProperty("hwnd")
'将窗口置于最上面,因为GetPixel方法只能针对可见像素使用 extern.SetForegroundWindowhWndSource
'取得设备上下文句柄 hDCSource = Clng(Extern.GetDC(hWndSource))
'取得相关控件的像素(1,1)点的背景色 backColor = Clng(Extern.GetPixel(hDCSource, Clng(1),Clng(1))) MsgBoxbackColor
'释放设备上下文句柄 Extern.ReleaseDChWndSource, hDCSource |
问题 17-5.如何使用Windows API模拟键盘操作
'声明API:键盘事件keybd_event extern.Declare micVoid,"keybd_event","user32" ,"keybd_event", _ micbyte,micbyte,miclong,miclon '声明API:虚拟按键码映射MapVirtualKey extern.Declare micLong,"MapVirtualKey","user32","MapVirtualKeyA", _ micLong, micLong
Const KEYEVENTF_EXTENDEDKEY = &H1 Const KEYEVENTF_KEYUP = &H2 Const KEYEVENTF_KEYDOWN = &H0
Sub KeyDown(KeyAscii) keyCode = extern.MapVirtualKey(KeyAscii, 0) '触发按键按下事件 extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYDOWN, 0 End Sub
Sub KeyUp(KeyAscii) keyCode = extern.MapVirtualKey(KeyAscii, 0) '触发按键抬起事件 extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYUP, 0 End Sub
Sub KeyPress(KeyAscii) KeyDownKeyAscii KeyUpKeyAscii End Sub |
对“计算器”使用以上代码
'声明键值常量 Const vbKey1 = 49 Const vbKey2 = 50 ConstvbKeyAdd = 107 ConstvbKeyReturn = 13
SystemUtil.Run"calc.exe" Window("title:=Calculator").Activate Call KeyPress(vbKey1) Call KeyPress(vbKeyAdd) Call KeyPress(vbKey2) Call KeyPress(vbKeyReturn) |
使用以上代码模拟CTRL+ALT+S
'声明键值常量 ConstvbKeyControl = 17 ConstvbKeyAlt = 18 ConstvbKeyS = 83
Call KeyDown(vbKeyControl) Call KeyDown(vbKeyAlt) Call KeyDown(vbKeyS) Call KeyUp(vbKeyS) Call KeyUp(vbKeyAlt) Call KeyUp(vbKeyControl) |
摘要:
随着软件测试的地位逐步提高,测试的重要性逐步显现,测试工具的应用已经成为了普遍的趋势。目前用于测试的工具已经比较多了,这些测试工具一般可分为:白盒测试工具、黑盒测试工具、性能测试工具,另外还有用于测试管理(测试流程管理、缺陷跟踪管理、测试用例管理)的工具。
总的来说,测试工具的应用可以提高测试的质量、测试的效率。但是在选择和使用测试工具的时候,应该看到,在测试过程中,并不是所有的测试工具都适合我们使用,同时,有了测试工具、会使用测试工具并不等于测试工具真正能在测试中发挥作用。因此,要发挥测试工具的价值,必须根据公司的实际情况合理选择测试工具, 本文拟从测试工具的选择和使用方面着手,讲述一点个人的心得,仅供参考
关键词:白盒测试工具集、黑盒测试工具集、测试管理工具集、自动化测试工具集
一、白盒测试工具集
白盒测试工具一般是针对代码进行测试,测试中发现的缺陷可以定位到代码级,根据测试工具原理的不同,又可以分为静态测试工具和动态测试工具。公司目前的测试水平尚不具备使用白盒测试工具进行代码测试的能力,这里只作简单介绍
1、静态测试工具
静态测试工具直接对代码进行分析,不需要运行代码,也不需要对代码编译链接,生成可执行文件。静态测试工具一般是对代码进行语法扫描,找出不符合编码规范的地方,根据某种质量模型评价代码的质量,生成系统的调用关系图等。静态测试工具的代表有Telelogic公司的Logiscope软件、PR公司的PRQA软件。
2、动态测试工具
动态测试工具与静态测试工具不同,动态测试工具的一般采用"插桩"的方式,向代码生成的可执行文件中插入一些监测代码,用来统计程序运行时的数据。其与静态测试工具最大的不同就是动态测试工具要求被测系统实际运行。
动态测试工具的代表有Compuware公司的DevPartner软件、Rational公司的Purify系列等。
Parasoft白盒测试工具集
Compuware白盒测试工具集
Xunit白盒测试工具集
二、黑盒测试工具集
黑盒测试工具适用于黑盒测试的场合,黑盒测试工具包括功能测试工具和性能测试工具。黑盒测试工具的一般原理是利用脚本的录制(Record)/回放(Playback),模拟用户的操作,
然后将被测系统的输出记录下来同预先给定的标准结果比较。黑盒测试工具可以大大减轻黑盒测试的工作量,在迭代开发的过程中,能够很好地进行回归测试
黑盒测试工具的代表有Rational公司的TeamTest、Robot,Compuware公司的QACenter,另外,专用于性能测试的工具包括有Radview公司的WebLoad、Microsoft公司的WebStress等工具。
主流黑盒功能测试工具集
主流黑盒性能测试工具集
三、测试管理工具典型产品比较
测试管理工具用于对测试进行管理。一般而言,测试管理工具对测试计划、测试用例、测试实施进行管理,并且测试管理工具还包括对缺陷的跟踪管理。
测试管理工具的代表有Rational公司的Test Manager、Compureware公司的TrackRecord等软件。
四、商业化自动测试工具比较
五、测试工具的选择
面对如此多的测试工具,对工具的选择就成了一个比较重要的问题。我们在考虑选用工具的时候,建议从以下几个方面来权衡和选择。
功能
功能应该是我们最关注的内容,选择一个测试工具首先就是看它提供的功能。当然,这并不是说测试工具提供的功能越多就越好,在实际的选择过程中,适用才是根本。事实上,目前市面上同类的软件测试工具之间的基本功能都是大同小异,各种软件提供的功能也大致相同,只不过有不同的侧重点。除了基本的功能之外,以下的功能需求也可以作为选择测试工具的参考:
报表功能;测试工具生成的结果最终要由人进行解释,而且,查看最终报告的人员不一定对测试很熟悉,因此,测试工具能否生成结果报表,能够以什么形势提供报表是需要考虑的因素。
测试工具的集成能力;测试工具的引入是一个长期的过程,应该是伴随着测试过程改进而进行的一个持续的过程。因此,测试工具的集成能力也是必须考虑的因素,这里的集成包括两个方面的意思:首先,测试工具能否和开发工具进行良好的集成;其次,测试工具能够和其他测试工具进行良好的集成。
操作系统和开发工具的兼容性;测试工具可否跨平台,是否适用于公司目前使用的开发工具,这些问题也是在选择一个测试工具时必须考虑的问题。
价格
除了功能之外,价格就应该是最重要的因素了。目前测试工具的价格普遍偏高,有的甚至是"天文数字",在这方面只能建议公司先使用网上盗版或破解的工具,但是测试的准确性得不到可靠得保证
六、测试工具在实际中运用的瓶颈
许多引入测试软件的公司并没有能够让测试软件发挥应有的作用,其主要原因我总结为三个方面:
1、没有考虑到公司的实际情况,盲目引入测试工具
首先要明确一点,并不是每种测试工具都适合公司目前的实际情况。一些公司怀着美好的愿望花了不小的代价引入测试工具,半年一年以后,测试工具却成了摆设,究其原因,就是没有能够考虑公司的现实情况,不切实际地期望测试工具能够改变公司的测试现状,从而导致了失败。建议:公司可以考虑先引入黑盒测试工具和测试管理工具。
2、没有形成一个良好的使用测试工具的环境
换句话说,就是没有能够形成一种机制让测试工具真正能够发挥作用。例如,白盒测试工具的一般使用场合是在单元测试阶段,而单元测试是由开发人员完成,如果没有流程来规范开发人员的行为,在项目进度压力比较大的情况下,开发人员很可能就会有意识地不使用测试工具,来逃避问题。在这种情况下,就必须形成一种有约束力的机制来强制对测试工具的使用。建议:将测试工具的使用明确定义进公司的开发流程,我认为是一种比较好的方式。
3、没有进行有效的测试工具的培训
测试工具的使用者必须对测试工具非常了解,在这方面,有效的培训是必不可少的。测试工具的培训是一个长期的过程,不是通过一两次讲课的形式就能达到良好的效果。而且,在实际的使用测试工具的过程中,测试工具的使用者可能还存在着这样那样的问题,这也需要有专人负责解决,否则的话,对于测试工具使用者的积极性是很大的打击。公司在进行测试工具的培训时,建议可以通过一系列的学习和交流,从针对开发高层的《测试工具基本概念培训》到针对测试工具实际使用者的《测试工具使用培训》,再到交流性质的《测试工具应用交流研讨会》,再到定期发出的《测试工具应用问答》,来提高目前测试工具的应用和测试人员的基本功
七、总结
综上所述目前公司在测试工具引入上应该抱着谨慎的态度,先试用共享或免费软件,待公司开发规模,质量管理力度,测试管理等达到一定深度时再考虑引入正版收费软件。其次,测试管理工具的引入优先与其他测试工具的引入,原因之一是测试管理手段的科学化,对测试工作具有指导与规范作用;其二,在目前公司独立测试从无到有逐步发展的里程中,找到适合公司自身特点的管理理念与方法显得更为迫切;其三,目前公司测试人员的水平对引入相对掌握难度较低的测试管理工具更能迅速上手;其四,目前共享或免费的测试管理工具可选择的余地较广,国产成熟产品也较多,且测试管理工具往往融合了过程管理的流程。
构建Python+Selenium2自动化测试环境完成之后,就需要测试支持python的selenium的版本是否都支持在不同浏览器上运行,当前我们分别在三个最通用的浏览器上通过脚本来测试。
1、在IE浏览器上运行测试脚本,首先需要下载IEDriverServer.exe,放在IE浏览器的安装目录且同级目录下,脚本如下:
import os from selenium import webdriver from selenium.webdriver.common.keys import Keys iedriver = "C:\Program Files\Internet Explorer\IEDriverServer.exe" os.environ["webdriver.ie.driver"] = iedriver driver = webdriver.Ie(iedriver) driver.get(http://www.python.org) assert "Python" in driver.title elem = driver.find_element_by_name("q") elem.send_keys("selenium") elem.send_keys(Keys.RETURN) assert "Google" in driver.title driver.close() driver.quit() |
2、在Chrome浏览器上运行测试脚本,首先需要下载ChromeDriver.exe,放在Chrome浏览器的安装目录且同级目录下,脚本如下:
import os from selenium import webdriver from selenium.webdriver.common.keys import Keys chromedriver = "C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe" os.environ["webdriver.chrome.driver"] = chromedriver driver = webdriver.Chrome(chromedriver) driver.get(http://www.python.org) assert "Python" in driver.title elem = driver.find_element_by_name("q") elem.send_keys("selenium") elem.send_keys(Keys.RETURN) assert "Google" in driver.title driver.close() driver.quit() |
3、在Firefox浏览器上运行测试脚本,具体如下:
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Firefox() driver.get(http://www.python.org) assert "Python" in driver.title elem = driver.find_element_by_name("q") elem.send_keys("selenium") elem.send_keys(Keys.RETURN) assert "Google" in driver.title driver.close() driver.quit() |
总结:通过以上三个不同浏览器上的测试,说明selenium在python中的运用于其Java版本都是一样。由于Firefox是默认安装路径,webdriver可以正常访问找到他,如果非系统默认安装路径,则需要跟IE和Chrome一样来设置driver路径。
相关链接:
构建Python+Selenium2自动化测试环境(一)
第九章库函数文件
库函数文件是包含VBScript脚本的纯文本格式文件,用来声明方法,变量,类等。库函数文件可以用任意后缀名,最常用的是VBS或者TXT。库函数文件可以用来组织存放不同功能的代码。它提供了在不同的QTP脚本中分享代码的方法。下面两节介绍加载库函数文件的两种方法。
关联一个全局库函数文件
通过这种方式库函数文件的同一实例可以被当前测试的所有Action共享和访问。如图9-1,打开 Test->Settings… ->Resources (标签页),添加库函数文件。
图9-1 Test Resource配置
小提示1:多个库函数文件加载顺序是从下到上。如果有两个库函数文件包含相同函数,那么会使用更靠近顶部的。
小提示2:如果库函数文件B依赖库函数文件A中的内容,库函数文件A应在列表中更靠近底部。
小提示3:QTP使用全路径名存放库函数文件。作为推荐选项,我们可以使用文件相对路径,如"..\test.vbs"
运行时动态加载本地库函数文件
QTP提供ExecuteFile方法可以在运行时动态加载库函数文件。使用这种方法时库函数文件及其内容只能在ExecuteFile执行的那个Action中可见。下面是一些例子:
'通过绝对路径加载库函数文件 ExecuteFile "C:\Test.vbs" '通过相对路径加载库函数文件 currentTestDir = Environment("TestDir") vbsFilePath = currentTestDir& "\..\..\CommonLibs\Test.vbs" ExecuteFilevbsFilePath '从Quality Center加载库 ExecuteFile "[QC-ATTACH];;Subject\CommonLibs;;\Test.vbs" |
小提示:如果ActionA和ActionB都通过ExecuteFile加载了test.vbs,同时ActionA调用ActionB,要注意他们对于所有test.vbs的变量和方法都只使用自己的副本和单独实例。
运行时动态加载全局库函数文件
如之前描述,在一个Action中直接使用ExectueFile方法只能使库函数文件在当前Action可见。但是每个QTP测试脚本可能需要一组全局库,使得对其中所有的Action都可用。取代直接在Action中使用ExecuteFile来加载库的方法,我们在某个全局库中加载库函数文件,那么它将对所有Action可用。
'C: \LibLoader.vbs Public Function ExecuteFileGlobal (ByValfileName) ExecuteFilefileName End Function |
我们可以将以上代码保存在一个VBS文件中并跟测试关联,使得在任意Action中都能通过调用ExecuteFileGlobal方法来加载文件。这样加载的文件在所有Action中都可以使用。
'在全局区域加载文件 ExecuteFileGlobal "C:\Test.vbs" |
但是当多个Action反复调用ExecuteFileGlobal会使某个库函数文件加载多次,这样每次都会破坏当前库函数文件中的全局变量的状态。
这个问题可用使用下面的方法解决。我们给ExecuteFileGlobal方法增加一个加载标记,当它为False时库函数文件就不会加载。可以通过给所有使用ExecuteFileGlobal方法加载的库函数文件创建一个全局字典来实现。库函数文件的路径用来判断这个库是否被加载过。
'C: \LoadLibrary.vbs Dim loadedFiles Set loadedFiles = CreateObject("Scripting.Dictionary") loadedFiles.CompareMode = vbTextCompare 'ExecuteFileGlobal方法动态加载文件 'Inputs - strFile: 需加载的完整文件名 ' reload: 是否重新加载已载入的文件 Public Function ExecuteFileGlobal (ByValstrFile,ByValreLoad) '判断reload为 False ,之后检查文件是否加载过 If reload = False and loadedFiles.Exists (strFile) then ExecuteFileGlobal = False Exit Function End if '加载库函数文件 ExecuteFilestrFile '将文件加入字典列表 loadedFiles (strFile) = True ExecuteFileGlobal = True End Function |
通过一个例子可以更好理解上面代码。首先我们创建一个要动态加载的库函数文件。
以下代码演示ExecuteFileGlobal的使用方法
'在全局区域加载testa.vbs ExecuteFileGlobal "C:\testa.vbs", False Msgbox X '显示 2 X = X + 2 '在全局区域加载testa.vbs,如果已经加载则忽略 ExecuteFileGlobal "C:\testa.vbs", False Msgbox X '显示4 ''在全局区域重新加载testa.vbs ExecuteFileGlobal "C:\testa.vbs", True Msgbox X '显示 2 |
问题 9-1. 如何动态定义全局变量
有时我们需要动态在两个或多个Action中共享变量值。使用加载库函数文件的相同概念,我们可以在运行时创建全局变量。
Declare.vbs 'C: \Declare.vbs Sub ExecuteGlobalCode (sStatement) ExecuteGlobalsStatement End Sub Action1: '在全局范围执行代码 ExecuteGlobalCode "Dim strText" strText = "TarunLalwani" Action2: '将显示"TarunLalwani" MsgBoxstrText |
理解执行作用域
理解测试脚本中全局作用域和本地作用域的区别是很重要的。
● 全局作用域是QTP加载所有测试资源和场景恢复库所在。测试脚本中的所有Action都可以访问
● 本地作用域是指所有在Action中定义的作用区域,不可被此Action之外所访问
图9-2描述了包含两个Action的QTP脚本的作用域视图,来表述QTP如何工作。
● 当脚本启动时QTP创建全局作用域
● QTP首先添加所有场景恢复库。按照关联顺序从上到下
● 场景恢复库之后,QTP加载所有关联在 Test->Settings…->Resource (标签)下的文件。加载的顺序是从下到上
● 之后QTP根据测试定义的工作流程按顺序调用每个Action。针对每个Action,QTP创建一个私有的本地作用域。此作用域在每个Action周期建立和释放
● 在Action1中定义的方法不会被其他Action或者全局作用域访问到
图9-2 QTP运行作用域:本地和全局作用域
小提示:如果多个全局库中有同名方法,那么最后一个加载的那个库中的方法会被调用。
Option Explicit的适用性
在库函数文件头部的"Option Explicit"声明允许程序员对所有使用的变量做强制变量声明。但我们可以看到即便在某些关联的库中有"Option Explicit"声明,对于没有声明的变量也没有抛出错误。
这个出现的原因是源于全局作用域建立的机制。我们需要在所有全局作用域中而不能只在个别全局库函数文件中使用"Option Explicit"。强制变量声明"Option Explicit"需要放在所有使用的库函数文件中,如果有遗漏,QTP就不会在全局域强制使用变量声明。
全局作用域内执行本地作用域代码
我们之前看过如何在本地作用域加载库函数文件("运行时动态加载本地库函数文件")以及如何从本地加载全局作用域库函数文件("运行时动态加载全局库函数文件")。
有时为了维护脚本我们可能需要在Action之前或之后增加代码。这种维护可能涉及多个数量的脚本。而QTP只允许一次打开一个脚本,所以编辑多个脚本是相当费时的工作。为了避免这种情形我们可以在所有Action中调用两个特殊的方法,代码如下:
'反射任何需要在Action之前执行的代码为语句并执行 Execute GetActionStart() 'Action相关的代码 '执行任何需要在Action之后执行的代码 Execute GetActionEnd() |
GetActionStart和GetActionEnd方法返回空值或者是需要执行的一段代码。下面是这两个方法的实现。
'每个Action之前调用的方法 '这个方法允许在Action的本地作用域动态执行代码,需要按以下格式在Action开始时调用 '执行GetActionStart() Function GetActionStart() '缺省没有执行代码 GetActionStart = "" '获取需要调用这个方法的Action名字 sAction = LCase(Environment("ActionName")) If InStr(sAction,"main") Then GetActionStart = "ExecuteFilePathFinder.Locate(""Workaround.vbs"")" End If End Function '每个Action最后调用的方法 '这个方法允许在Action的本地作用域动态执行代码,需要按以下格式在Action结束时调用 '执行GetActionEnd() Function GetActionEnd() '缺省没有执行代码 GetActionEnd = "" ''获取需要调用这个方法的Action名 sAction = Environment("ActionName") ''获取需要调用这个方法的Action名 sAction = LCase(Environment("ActionName")) 。。。 If InStr(sAction,"main") Then GetActionEnd = "ExecuteFilePathFinder.Locate(""Workaround.vbs"")" End If 。。。 End Function |
(未完待续)
版权声明:51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像。51testing软件测试网欢迎与业内同行进行有益的合作和交流,如果有任何有关内容方面的合作事宜,请联系我们。
相关链接:
QTP自动化测试权威指南 连载(一)
QTP自动化测试权威指南 连载(二)
QTP自动化测试权威指南 连载(三)