个人理解,数据库性能最关键的因素在于IO,因为操作内存是快速的,但是读写磁盘是速度很慢的,优化数据库最关键的问题在于减少磁盘的IO,就个人理解应该分为物理的和逻辑的优化, 物理的是指oracle产品本身的一些优化,逻辑优化是指应用程序级别的优化物理优化的一些原则:
1)Oracle的运行环境(网络,硬件等)
2)使用合适的优化器
3)合理配置oracle实例参数
4)建立合适的索引(减少IO)
5)将索引数据和表数据分开在不同的表空间上(降低IO冲突)
6)建立表分区,将数据分别存储在不同的分区上(以空间换取时间,减少IO)
逻辑上优化:
1)可以对表进行逻辑分割,如中国移动用户表,可以根据手机尾数分成10个表,这样对性能会有一定的作用
2)Sql语句使用占位符语句,并且开发时候必须按照规定编写sql语句(如全部大写,全部小写等)oracle解析语句后会放置到共享池中, 如:
select * from Emp where name=?这个语句只会在共享池中有一条,而如果是字符串的话,那就根据不同名字存在不同的语句,所以占位符效率较好
3)数据库不仅仅是一个存储数据的地方,同样是一个编程的地方,一些耗时的操作,可以通过存储过程等在用户较少的情况下执行,从而错开系统使用的高峰时间,提高数据库性能
4)尽量不使用*号,如select * from Emp,因为要转化为具体的列名是要查数据字典, 比较耗时
5)选择有效的表名
对于多表连接查询,可能oracle的优化器并不会优化到这个程度, oracle 中多表查询是根据FROM字句从右到左的数据进行的,那么最好右边的表(也就是基础表)选 择数据较少的表,这样排序更快速,如果有link表(多对多中间表),那么将link表放最右边作为基础表,在默认情况下oracle会自动优化,但是如果配置了优化器的情况下,可能不会自动优化,所以平时最好能按照这个方式编写sql
6)Where字句规则:
Oracle 中Where字句时从右往左处理的,表之间的连接写在其他条件之前,能过滤掉非常多的数据的条件,放在where的末尾, 另外!=符号比较的列将不使用索引,列经过了计算(如变大写等)不会使用索引(需要建立起函数), is null、is not null等优化器不会使用索引
7)使用Exits Not Exits 替代 In Not in
8)合理使用事务,合理设置事务隔离性,数据库的数据操作比较消耗数据库资源的,尽量使用批量处理,以降低事务操作次数
前言
软件测试在软件诞生的那一天就开始了,越来越多的公司和组织获得了软件测试的巨大回报,这是提高软件质量最有效的方法,也是提高公司产品质量的重要手段。
曾经一个朋友聊天时说过,一个90年代的程序设计师和一个90年代的测试工程师,那么到了我们现代的这个社会,程序设计师可能不知道如何下手,但是测试工程师还是可以按照他的思路来测试这个产品(对于较简单的非网络软件)。
起初听到这个事情很不以为然,但是仔细坐下来好好想想,这里面隐藏着一个软件测试方面的巨大的难题。那就是我们的软件测试方法一直都没有改变过,曾经很多人提出过这方面的理论和技术,但是很多都是以失败告终了。那么为什么软件测试改进这么难,编程语言在层出不穷的变换着,唯独测试方面停滞不前。仔细想一想,是因为软件的多样性,曾经有学者提出建立像维基百科那样,建立一个测试百科,由世界各地的测试工程师上传自己的测试用例,也提出过携带环境测试等等一些理论。所以我们对软件测试新方法迫不及待。
第一节 软件失效
当我们看到这个名词的时候,我相信很多测试工程师都会有同感,在你们的工作过程中发现过很多软件失效,“人类本身就是一个麻烦的制造者”,我们不仅扪心自问,“我们是否可以真正以来软件处理这些重要的全球性任务?对于许多灾难“船只抛锚”、“火箭爆炸”、“金钱损失”,甚至于“夺走人类的生命”。人类并不完美,难免会犯错误,任何人。
第二节 商业中的软件测试
如今软件测试已经系统化的应用到了商业软件测试中,但是在真正的测试中往往是这样的,当我们测试到一定的程度的时候,bug的数量不在增加了,这个使我们往往很苦恼,从测试用例中一遍一遍的运行,希望发现bug。但是很多的时候我们的测试经理很略了一个很大的方面,那就是测试工程师的心理,我们往往在很苦闷的寻找一个东西,往往变现的很是急躁,但是如果我们有了地图,或者有了提示,那么我们再寻找的话,往往会轻松很多。我们暂且称之为测试瓶颈。
这个时候我们需要转变测试方法,举一个例子,农民在喷洒农药的时候,时间长了,有一些虫子不但不死,反而对其的药性有抵抗力,这是时候农民往往回换一种药。软件测试亦是如此,这个时候我们就得换一种测试方面。这是软件测试原理中的第五条:杀虫剂侼论。
第三节 探索性软件测试
第一次看到这个词语你可能会感到惊讶,从此以上面我们可以看出,那就是在探索中测试。
那么我们从这里在分为:局部探索性软件测试、全局探索性软件测试以及混合探索性软件测试。
局部探索性软件测试:
进入这个话题之前,我们先看一个比喻性的招聘广告:
急需一名软件测试人员,该职位要求根据那些乱七八糟且只有半截的规格说明书(如果还能找到的话)来测试一个高度复杂且基本不带任何文档的软件产品。不要指望当初的开发人员,他们基本不愿也不会帮助你。该产品的使用环境广泛,支持多用户、多平台、多语言和其他很多必须支持的环境。我们不清楚如何定义它们,但是安全性和性能是最重要的,而且软件发布后不允许处任何问题,否则我们就玩完了。
我们必须承认上面说的都是反话。但是这里提到情况,我敢打赌他们是不会招聘到人的。
这个广告告诉我们,测试工程师必须有完整的产品规格说明书,必须清楚产品框架,必须了解产品的使用过程和功能。
测试就是有所改变,有所不变。
1)你必须判断软件运行的表现是否符合设计的预期?
2)当用户为了某个功能购买了软件,可是该软件时候实现了这个功能?
3)软件运行时,是否足够快,足够安全,足够稳定?
那么在局部探索性软件测试我们可以依赖于以下几种:
1)合法输入和非法输入
2)输入筛选器
3)输入检查
4)异常处理代码
5)默认输入或者用户提供的输入?
6)常规输入还是非常规输入?
7)使用输出来指导输入选择
全局探索性软件测试:
我们暂且把全局探索性软件测试看着一次旅行,你到了摸一个大城市之后,比如英国伦敦,这个城市中会分为:商业区、历史区、旅游区、娱乐区、旅馆区、破旧区。
1、商业区测试类型:
商业区是一个城市的经济核心,相比软件,商业区就是软件中最主要的功能。
那么我们有以下几种测试方法,
1)指南测试法
要求测试人员通过阅读用户手册并严格按照手册的建议执行。如果手册描述了摸个特性以及如何使用该特性时,测试人员要特别留心那些指令。其目的是尽量忠实地执行用户手册中描述的每个场景。虽然许多帮助系统只描述了软件的特性,而不涉及场景,但他们一般对于英爱使用那些输入以及操作用户界面来执行软件的特性都会给出具体的建议。因此这个测试法不仅可以验证软件确实实现了手册中所描写和各种软件特性,并且还能验证手册的准确性。
2)卖点测试法
在一个城市中都有这个城市的亮点,我们也通常叫做卖点,比如北京天安门,王府井。香港的购物街。拉斯维加斯的赌城。
在软件测试中,我们的卖点往往就是我们广告上面说的最多的那个功能。那么测试人员可以在这些软件的卖点上面去测试。
3)地标测试法
我们去一个第一个往往首先会看地图,然后再看指南针。
在软件测试中,我们可以把主要的功能标注出来,这就是“地标”,然后按照前后顺序,依次运行。
4)快递测试法
在商业去中数据的信息量往往占了很大的比例。
软件测试中,我们可以把一个输入数据作为快递,标记,跟着这个数据,直到整个生命周期。查看是否符合要求。
5)深夜测试法
我们往往在白天和网上会看到商业区的繁华,但是在凌晨以及深夜,那么这个繁华区往往会有另一番风趣。
软件测试中,就是在深夜运行这个程序,然后查看软件在深夜运行的记录。
2、历史区测试法
1)恶邻测试法
在我们旅游的城市,我们往往会根据导游的提示,有目的的去访问那里,但是,那些往往我们不去访问的地方往往是肮脏的。
那么在我们的软件里面,我们根据软件说明书,按照编辑给我们设置的路径去操作,那么这个时候我们假如打破逻辑,就会找出很多未知的缺陷。
2)博物馆测试法
博物馆是战士古董的地方,在软件里面,我们把一些老的代码比作这些代码,一些程序员在引入这些代码的过程中,往往没有修改就运行了,我们的测试目的是在这些老代码的基础上,看能不能在新的功能上正确的实现。
3)上一版测试法
这点类似于回归测试,我们在这里不相信阐述。
3、娱乐区测试类型
1)配角测试法
我们在关注某一个产品的时候往往关注了这个产品的主要功能,而忽略的次要功能,例如:我们再测一个数据页面显示的功能,当我们输入相应的数据,页面很好的显示出来的,那么我们再其页面的右下方发现了一个打印按钮,这就是我们此方法的用武之地了。
2)深巷测试法
我们再旅游的时候,有些地方总有一些游客特别想去,但是有些地方游客很是不愿意光顾,比如,垃圾回收站,废品处理站。
在软件里面我们也可以这样做,假如:我们再跟踪一个数据的时候,我们往往关注的是这个数据能不能很好的读取或者被运算,我们都忽略一个很大的误区,好的设计者会很好的运用变量的生命周期耳朵,即:当这个数据不再使用的时候,那么就应该销毁,不这么的做的后果就是,数据没有被及时回收,内存不能释放,造成内存泄露。严重的时候甚至影响系统运行。
3)通宵测试法
人假如几天几夜不合眼的话,那么工作效率就会变差。
软件也是如此,虽然是没有生命的,但是他的每个变量和元素都是有生命周期,让软件长时间工作,同时记录其运行日志。一旦发生崩溃或者异常,我们就能很快的锁定。
旅游区测试类型
1)收藏家测试法
测试人员应该确保每一个输出的结果,编辑一个表格来表示的他,然后从中找出破绽
2)长路径测试法
我们在软件中假如一个功能到另外一个功能中间要进行很多操作,也许在操作的过程中就能发现bug。
3)超模测试法
这个测试法要求测试人员能够关注UI的每一个细节,输出显示字符的大小,按钮的大小,字符的长短。
4)测一送一测试法
“buy one get one free”,很简单,我们再运行程序的时候,同时运行一个拷贝,那么我们再两个程序同时去争抢一个内存的时候,或者时候运行导入,两个程序就会争夺一个导入文件,那么这个时候程序往往就会出错
旅馆区测试类型
1)取消测试法
有些程序在软件运行的过程中是不让被取消的,那么我们可以做,虽然有点抢人所爱,我们可以在运行的过程中,单机关闭,直接断掉计算机电源,在进程中杀掉这个进程。
2)懒汉测试法
在有一些软件中,我们往往会碰到系统默认值,那么我们可以更改这些值或者删除或者使用特殊符号。观察系统异常。
破旧区测试类型
1)逆向测试法
比如在一个打印程序中,系统会让用户选择打印那一页,我们输入字母,观察系统是不是有这方面的处理能力。
2)歹徒测试法
运用非法输入
3)错序输入法
比如时间格式,我们不按照提示输入会怎样?
4)强迫症输入法
我们一边又一边的输入数据,强迫软件运行
验收测试的主要内容
验收测试过程
验收测试的常用策略
验收测试报告
用户验收测试实例
1、验收测试的主要内容
● 验收测试是部署软件之前的最后一个测试操作。
● 验收测试的目的是:确保软件准备就绪,并且可以让最终用户将其用于执行软件的既定功能和任务。
验收测试的任务
● 验收测试是向未来的用户表明系统能够像预定要求那样工作。也就是验证软件的有效性。
● 验收测试的任务,即验证软件的功能和性能如同用户所合理期待的那样。
验收测试的主要内容
● 验收测试的主要内容有以下几个方面:
1.制定验收测试标准
2.配置项复审
3.实施验收测试
验收测试主要内容——制定验收标准
● 实现软件确认要通过一系列测试。验收测试同样需要制订测试计划和过程。
● 测试计划应规定测试的种类和测试进度,测试过程则定义一些特殊的测试用例,为的是在说明软件与合同要求是否一致。
● 无论是计划还是过程,都应该着重考虑以下几个方面:
1.软件是否满足合同规定的所有功能和性能
2.文档资料是否完整
3.准确人机界面
4.其他方面(例如,可移植性、兼容性、错误恢复能力和可维护性等)是否令用户满意。
● 验收测试主要内容——实施验收测试
● 验收测试的准备工作做好之后,就要进入验收测试的实施阶段。
● 在此阶段里,需要采用一些常用的验收测试策略进行,例如:α测试,β测试等。
● 实施验收测试是整个验收测试过程中的核心部分。
验收测试主要内容——配置项复审
● 验收测试的另一个重要环节是配置项复审。在进行验收测试之前,必须保证所有软件配置项都能进入验收测试,只有这样才能保证最终交付给用户的软件产品完整性和有效性。
● 复审的目的:保证软件配置齐全、分类有序,并且包括软件维护所必须的细节。
2、验收测试过程
● 进行验收测试,必须要了解验收测试的过程。只有按照验收过程的步骤进行,才能保证验收测试的顺利实施。
验收测试过程的主要内容
1.软件需求分析:了解软件功能和性能要求、软硬件环境要求等,并特别要了解软件的质量要求和验收要求。
2.编制《验收测试计划》和《项目验收准则》:根据软件需求和验收要求编制测试计划,制定需测试的测试项,制定测3.试策略及验收通过准则,并经过客户参与的计划评审。
3.测试设计和测试用例设计:根据《验收测试计划》和《项目验收准则》编制测试用例,并经过评审。
4.测试环境搭建:建立测试的硬件环境、软件环境等。(可在委托客户提供的环境中进行测试)
5.测试实施:测试并记录测试结果。
6.测试结果分析:根据验收通过准则分析测试结果,作出验收是否通过及测试评价。
7.测试报告:根据测试结果编制缺陷报告和验收测试报告,并提交给客户。
验收测试过程流程图

验收测试步骤
步骤1:验收测试业务恰谈
双方就测试项目及合同进行洽谈
步骤2:签订测试合同
步骤3:开发方提交测试样品及相关资料
开发方需提交的文档有:
基本文档:(验收测试必需的文档),用户手册,安装手册,操作手册,维护手册,软件开发合同,需求规格说明书,软件设计说明,软件样品(可刻录在光盘)
特殊文档:(根据测试内容不同,委托方所需提交下列相应的文档),软件产品开发过程中的测试记录,软件产品源代码。
步骤4:开发方提交测试样品及相关资料
步骤5:编制测试计划并通过评审
步骤6:进行项目相关知识培训
步骤7:测试设计
评测中心编制测试方案和设计测试用例集。
步骤8:方案评审
评测中心测试组成员、委托方代表一起对测试方案进行评审。
步骤9:实施测试
评测中心对测试方案进行整改,并实施测试。在测试过程中每日提交测试事件报告给委托方。
步骤10:编制验收测试报告并组织评审
评测中心编制验收测试报告,并组织内部评审。
步骤11:提交验收测试报告
评测中心提交验收测试报告。
3、验收测试的常用策略
● 施验收测试的常用策略有三种,它们分别是:
1.正式验收测试
2.非正式验收或 α 测试
3.β 测试
● 选择的策略通常建立在合同需求、组织和公司标准以及应用领域的基础上。
正式验收测试
● 正式验收测试是一项管理严格的过程,它通常是系统测试的延续。计划和设计这些测试的周密和详细程度不亚于系统测试。选择的测试用例应该是系统测试中所执行测试用例的子集
1.正式验收测试的两种方式:
2.在某些组织中,开发组织(或其独立的测试小组)与最终用户组织的代表一起执行验收测试。
在其他组织中,验收测试则完全由最终用户组织执行,或者由最终用户组织选择人员组成一个客观公正的小组来执行。
● 正式验收测试形式的优点包括:
1.要测试的功能和特性都是已知的。
2.测试的细节是已知的并且可以对其进行评测。
3.这种测试可以自动执行,支持回归测试。
4.可以对测试过程进行评测和监测。
5.可接受性标准是已知的。
● 正式验收测试形式的缺点包括:
1.要求大量的资源和计划。
2.这些测试可能是系统测试的再次实施。
3.可能无法发现软件中由于主观原因造成的缺陷,这是因为您只查找预期要发现的缺陷。
非正式验收或 α 测试
● 在非正式验收测试中,执行测试过程的限定不象正式验收测试中那样严格。在此测试中,确定并记录要研究的功能和业务任务,但没有可以遵循的特定测试用例。测试内容由各测试员决定。
● 这种验收测试方法不象正式验收测试那样组织有序,而且更为主观。
● 大多数情况下,非正式验收测试是由最终用户组织执行的。
● 非正式验收或 α 测试的优点包括:
1.要测试的功能和特性都是已知的。
2.可以对测试过程进行评测和监测。
3.可接受性标准是已知的。
4.与正式验收测试相比,可以发现更多由于主观原因造成的缺陷。
● 非正式验收或 α 测试的缺点包括:
1.要求资源、计划和管理资源。
2.无法控制所使用的测试用例。
3.最终用户可能沿用系统工作的方式,并可能无法发现缺陷。
4.最终用户可能专注于比较新系统与遗留系统,而不是专注于查找缺陷。
5.用于验收测试的资源不受项目的控制,并且可能受到压缩。
● β 测试
在上述三种验收测试策略中, β 测试需要的控制是最少的。在 β测试中,采用的细节多少、数据和方法完全由各测试员决定。各测试员负责创建自己的环境、选择数据,并决定要研究的功能、特性或任务。各测试员负责确定自己对于系统当前状态的接受标准。
● β 测试由最终用户实施,通常开发(或其他非最终用户)组织对其的管理很少或不进行管理。
● β测试是所有验收测试策略中最主观的。
● β 测试的优点是:
1.测试由最终用户实施。
2.大量的潜在测试资源。
3.提高客户对参与人员的满意程度。
4.与正式或非正式验收测试相比,可以发现更多由于主观原因造成的缺陷。
● β 测试的缺点是:
1.未对所有功能和/或特性进行测试。
2.测试流程难以评测。
3.最终用户可能沿用系统工作的方式,并可能没有发现或没有报告缺陷。
4.最终用户可能专注于比较新系统与遗留系统,而不是专注于查找缺陷。
5.用于验收测试的资源不受项目的控制,并且可能受到压缩。
6.可接受性标准是未知的。
7.需要更多辅助性资源来管理β 测试员。
4、验收测试报告
● 做为测试的结果,需要给出测试报告。验收测试也不例外。
● 在验收测试的结束部分,需要以文档的形式提供“验收测试报告”做为对验收测试结果的一个书面说明。
验收报告的模板
● 验收报告一般分为三个部分:头部,主体,尾部
● 验收报告的头部应该标明项目的一些基本信息,参考格式如下:
项目验收报告
项目名称:
产品名称:
产品版本:
客户名称:
供应方:
验收日期:
● 验收报告主体内容可以参考以下的模板格式:
目录
....
1 前言
1.1 编写目的
...
1.2 项目背景
...
2 功能验收
验收项类别 验收项名称 说明 是否通过验收 备注
3 性能验收
验收项类别 验收项名称 说明 是否通过验收 备注
4 交付物验收
验收项类别 验收项名称 说明 是否通过验收 备注
硬 件
软 件(安装光盘)
文 档
......
5 验收结论
......
● 在验收报告的尾部,需要注明验收报告的时间,验收单位(个人)等验收测试相关信息。参考格式如下:
验收方: 提供方:
项目负责人签字: 项目负责人签字:
日期: 日期:
5、用户验收测试实施
用户验收测试可以分为两个大的部分:软件配置审核和可执行程序测试,其大致顺序可分为:
1.文档审核
2.源代码审核
3.配置脚本审核
4.测试程序或脚本审核
5.可执行程序测试。
软件配置审核:
对于一个外包的软件项目而言,软件承包方通常要提供如下相关的软件配置内容:
―可执行程序
―源程序
―配置脚本
―测试程序或脚本。
● 主要的开发类文档:
《需求分析说明书》
《概要设计说明书》
《详细设计说明书》
《数据库设计说明书》
《测试计划》
《测试报告》
《程序维护手册》
《程序员开发手册》
《用户操作手册》
《项目总结报告》
● 主要的管理类文档:
《项目计划书》
《质量控制计划》
《配置管理计划》
《用户培训计划》
《质量总结报告》
《评审报告》
《会议记录》
《开发进度月报》
● 在开发类文档中,容易被忽视的文档有《程序维护手册》和《程序员开发手册》。
《程序维护手册》的主要内容包括:系统说明(包括程序说明)、操作环境、维护过程、源代码清单等,编写目的是为将来的维护、修改和再次开发工作提供有用的技术信息。
《程序员开发手册》的主要内容包括:系统目标、开发环境使用说明、测试环境使用说明、编码规范及相应的流程等,实际上就是程序员的培训手册。
● 通常,正式的审核过程分为5个步骤:
计划
预备会议(可选):对审核内容进行介绍并讨论
准备阶段:各责任人事先审核并记录发现的问题
审核会议:最终确定工作产品中包含的错误和缺陷
问题追踪
审核要达到的基本目标是:
根据共同制定的审核表,尽可能地发现被审核内容中存在的问题,并最终得到解决。
在根据相应的审核表进行文档审核和源代码审核时,还要注意文档与源代码的一致性。
在文档审核、源代码审核、配置脚本审核、测试程序或脚本审核都顺利完成后,就可以进行验收测试的最后一个步骤—可执行程序的测试。
可执行程序的测试包括功能、性能等方面的测试,每种测试也都包括目标、启动标准、活动、完成标准和度量等五部分。
要注意的是不能直接使用开发方提供的可执行程序用于测试,而要按照开发方提供的编译步骤,从源代码重新生成可执行程序。
在真正进行用户验收测试之前一般应该已经完成了以下工作(也可以根据实际情况有选择地采用或增加):
软件开发已经完成,并全部解决了已知的软件缺陷。
验收测试计划已经过评审并批准,并且置于文档控制之下。
对软件需求说明书的审查已经完成。
对概要设计、详细设计的审查已经完成。
对所有关键模块的代码审查已经完成。
对单元、集成、系统测试计划和报告的审查已经完成。
所有的测试脚本已完成,并至少执行过一次,且通过评审。
使用配置管理工具且代码置于配置控制之下。
软件问题处理流程已经就绪。
已经制定、评审并批准验收测试完成标准。
具体的测试内容通常可以包括:
● 安装(升级)
● 启动与关机
● 功能测试(正例、重要算法、边界、时序、反例、错误处理)
● 性能测试(正常的负载、容量变化)
● 压力测试(临界的负载、容量变化)
● 配置测试、平台测试、安全性测试、恢复测试(在出现掉电、硬件故障或切换、网络故障等情况时,系统是否能够正常运行)、可靠性测试等。
如果执行了所有的测试案例、测试程序或脚本,用户验收测试中发现的所有软件问题都已解决,而且所有的软件配置均已更新和审核,可以反映出软件在用户验收测试中所发生的变化,用户验收测试就完成了。
6.15 关于事务相关信息部分内容
事务的响应时间是我们平时经常关注的一项性能指标,除此之外,在结果概要信息图表中,您还会经常看到事务的最小值(Minimum)、平均值(Average)、最大值(Maximum)、标准偏差(Std. Deviation)和90%事务(90 Percent)等相关信息内容,这些数值代表什么?又是怎样得来的呢?
6.15.1 关于分析概要事务相关信息问题提出
尽管我们都是性能测试的从业人员,可是作为测试人员通常都有一个对事物“怀疑”的心理,在这里就表现为LoadRunner给出的这个结果信息是否可信?以及相应的结果信息是如何得到的?
这确实是一个很好的问题,但是,如何去证明LoadRunner 11.0的结果信息是正确的呢?大家在平时做功能测试的时候,是如何证明被测试的功能模块是正确的呢?相信作为测试从业者,我们都会异口同声地说:“我们都会设计很多测试用例,用例包括两部分:输入和预期的输出,如果根据测试用例在被测试的功能模块输入相应的数据,实际执行结果和预期结果一致,那么就认为此功能模块是正确的,否则就是失败的。”回答得非常好,那么性能测试是不是可以效仿功能测试呢?回答是肯定的,为了验证性能测试的执行结果的正确性和各个结果信息的数据来源,我们也需要事先组织一些数据,然后根据这些数据的内容算出预期的结果,再通过LoadRunner 11.0去实现我们的想法,观察最后执行的结果是否和我们预期的一致,当然,如果一致就是正确的了,不一致,当然就证明两者之间有一个是错误的,结合我们预期的设定来讲,当然是LoadRunner 11.0是错误的。
6.15.2 关于结果概要事务相关信息问题分析
这里我有一个想法就是,我们事先准备10个数字,即:1、2、3、4、5、6、7、8、9、10,从这组数字当中不难发现,最小的数值应该是1,最大的数值应该是10,这些数值的平均值为(1+2+3+4+5+6+7+8+9+10)/10=55/10=6.5,在这组数值里边90%的数值都会小于或等于9,只有1个数值大于9,即:数值10。
也许,聪明的读者朋友们已经想到了,我们是否可以借助LoadRunner 11.0的事务和思考时间来将我们的想法实现。“嗯,确实如此,我们的想法不谋而合”。
6.15.3 关于结果概要事务脚本设计及其相关设置
首先,我们可以在Virtual User Generator中编写一个脚本,即:
Action() { lr_start_transaction("思考时间测试事务"); lr_think_time(atoi(lr_eval_string("{thinktime}"))); lr_end_transaction("思考时间测试事务", LR_AUTO); return 0; } |
其中,“thinktime.dat”参数化文件内容包括数值1到10,共计10个整数值,如图6-178所示。

图6-178 “thinktime.dat”参数化文件内容
然后,设置“thinktime”参数的“Select next row:”为“Unique”,“Update value on:”为“Once”。
接下来,启动“Controller”让我们来设定一个场景,我们在参数化的时候一共参数化了10条数据记录,在场景设计的时候,也取10个虚拟用户,如图6-179所示。

图6-179 “Controller”场景设计对话框
当然,如果您关心在负载的时候,每个虚拟用户分别取到了哪些值,可以将测试执行日志打开,根据需要,这里我们单击图6-180红色区域所示按钮,则出现“Run-Time Settings”对话框,如图6-181所示。然后,选择“Log”页,请您根据自己的情况,选中日志的扩展情况,这里我们选中“Parameter substitution”选项。

图6-180 场景设计对话框

图6-181 “Run-Time Settings”对话框
而后,单击“Run”页,如图6-182所示,再单击图6-183的“Start Scenario”按钮,则开始执行场景。

图6-182 场景设计对话框

图6-183 场景执行对话框
您可以单击“Results>Analyze Results”菜单项或者单击工具条对应的功能按钮,如图6-184所示,就可以将执行完成后的结果调出来。

图6-184 场景执行对话框
6.15.4 如何解决结果概要信息不计入思考时间问题
测试结果出来后,首先,映入眼帘的是“Analysis Summary”图表信息,但是您是不是被“Transaction Summary”的数据惊呆了呢?参见图6-185所示,为什么图中所有的数值均为“0”呢?相信有很多朋友对这个结果也感到莫名其妙,再回头看看我们的脚本,脚本中使用了思考时间,即“lr_think_time()”函数,而在“Analysis”应用中在默认的情况下,是忽略思考时间的,所以就出现了这样的一个结果。那么如何使响应时间中包括思考时间呢?非常简单,您可以单击属性“Filter”,默认情况下该属性值为“do not Include Think Time”,单击该属性值后面的按钮,如图6-186所示。

图6-185 结果分析应用界面

图6-186 结果分析应用界面
单击
按钮后,则出现图6-187所示界面,单击“Think Time”过滤条件,在“Values”列选中“Include Think Time”复选框。

图6-187 结果概要分析过滤对话框
设定好过滤条件后,单击“Analysis Summary Filter”对话框的“OK”按钮,此时您会发现结果信息的内容发生了改变,先前为“0”的数值项现在已经有了数值,如图6-188所示方框部分内容。

图6-188 事务概要信息内容
(未完待续)
版权声明:51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像。51testing软件测试网欢迎与业内同行进行有益的合作和交流,如果有任何有关内容方面的合作事宜,请联系我们。
摘要:针对传统软件可靠性测试方法在对软件因长期使用软件性能下降,甚至完全失效这种严重影响软件可靠性的测试存在不足的现状,通过对软件自身特性以及软件可靠性估算面临问题的深入分析和研究,结合传统的软件可靠性测试方法,提出了基于操作剖面的软件可靠性压力测试思想和操作剖面、压力测试点相互结合、互为补充的软件可靠性测试方法,并给出了软件可靠性测试新方法实施的技术途径。该思想与方法既是对传统软件可靠性测试方法的一个大胆探索,也是对软件可靠性测试方法的一个有益补充。
关键词:软件缺陷;软件可靠性;压力测试;
0、引言
软件在计算机发展的不同阶段有不同的认识。计算机发展的初期,硬件在计算机应用中起决定作用,而软件,即程序,甚至是机器指令程序或汇编程序,是处于从属地位的。软件开发是以个体手工的方式进行,设计是人的智力行为,软件质量完全取决于个人的智力和编程技巧。随着计算机的发展,人们认识到软件使得计算机的计算能力大大提高,应用能力大大增强。于是在开发计算机应用系统时,硬件和软件同时考虑,而且开始编制应用支撑程序,如操作系统、数据库等。这时的生产方式是以小作坊的形式进行。到了后来,社会的各种应用需要对计算机提出了更高和更特别的要求,很多大型软件系统开发的工作量高达数千人年,指令数百万条或更多,如美国宇航飞船的软件系统有4000万条语句。而今,计算机的应用面越来越广,应用规模越来越大,应用过程越来越复杂,软件在计算机系统中的比重越来越大,软件成本在总成本中的比重正在逐年上升,而且这种趋势还在增加。这时人们感到传统的软件生产方式已不适应计算机发展的需要,需要把工程学的基本原理和方法引入到软件开发过程中,即软件工程思想。
事实上,无论计算机技术如何发展,计算机中的软件是人通过智力劳动产生的,其软件产品是人的思维结果,是一个逻辑部件,而不是一个物理部件。软件开发水平很大程度上取决于软件人员的教育、训练和经验的积累。由此软件具有与硬件或传统工业产品不同的特点:
(1)软件是一种逻辑实体,具有抽象性,人们必须通过观察、分析、思考、判断,才能了解它的功能、性能等特性;
(2)软件没有明显的制造过程,一旦研制开发成功,就可以大量拷贝同一内容的副本。所以对软件的质量控制,必须在软件开发方面下工夫;
(3)软件在使用过程中,没有磨损、老化的问题,但为了适应硬件、环境以及需求的变化而进行修改,这些修改常常会引入错误,导致软件失效率升高,软件质量降低。如果修改成本太高,质量风险太大,软件就会被抛弃;
(4)软件对硬件和环境有着不同程度的依赖性,由此带来了软件移植的问题;
(5)软件的开发至今尚未完全摆脱手工作坊式的开发方式,生产效率低。这对复杂软件,特别是今后会更加复杂的软件带来了是否能够控制其复杂性和时效性的问题;
(6)软件开发需要投入大量、高强度的脑力劳动,成本非常高,风险也大。现在软件的开销已大大超过了硬件的开销;
(7)许多软件的开发和运行涉及机构、体制和管理方式等问题,还会涉及到人们的观念和心理。这些人的因素,常常成为软件开发的困难所在,直接影响到项目的成败。
基于上述软件的特性,美国国防部中大量的软件系统其可靠性得不到保证,几乎没有不存在错误的软件系统。尽管人们在软件开发过程中采用各种软件工程方法,应用各种软件测试技术,但他们只能尽量发现错误、减少错误,却不可能彻底消除错误,无法实现真正意义上的无错软件,百分之百的可靠。
现今计算机硬件技术的发展,使得在计算机系统中的硬件可靠性越来越高,而软件可靠性的问题变得日益突出。在一些关键的应用领域,如航空、航天等,对软件可靠性的要求尤为重要。如在银行等服务性行业,其软件系统的可靠性也直接关系到自身的声誉和生存发展竞争能力。由于软件中存在缺陷、错误和故障使软件失效很有可能造成巨大的损失或惨重的灾难。研究结果表明:由于软件开发出现问题引起的系统失效与由于硬件设计或使用引起的失效之比是10:1。由此可见,软件在计算机系统中占有绝对重要的地位。于是,人们借鉴硬件可靠性理论,提出了“软件可靠性”概念,不再追求软件无错,而以统计的观点去判断软件满足用户使用要求的程度。
1、软件可靠性
软件可靠性借鉴了硬件可靠性的概念,即软件按规定的条件,在规定的时间内运行而不发生故障的能力。软件可靠性与硬件可靠性不同的是:软件可靠性不但与软件中存在的缺陷有关,而且与系统输入和系统使用有关。
从定义上看,评价或测试一个软件的可靠性,最主要的是要确定系统怎样输入、如何使用一整套的方法和策略。另一方面,软件可靠性是软件质量特性中重要的固有特性和关键因素,软件可靠性反映了用户的质量观点。而软件的故障是由于软件的质量存在问题——即它固有的缺陷导致错误,进而使系统的输出不满足预定的要求,造成系统的故障。所谓按规定的条件主要是指软件的运行(使用)环境,它涉及软件运行所需要的一切支持系统及有关的因素。如支持硬件、网络、操作系统及其它支持软件、输入数据、操作规程等。
尽管当前的软件可靠性定义借用了硬件可靠性的定义,但事实上软件可靠性因软件的特性它与硬件可靠性相比较是有很大的差别的,如:
(1) 硬件有老化损耗现象,硬件失效是物理故障,是器件物理变化的必然结果。软件不发生变化,没有磨损现象,但软件由于长期使用软件性能下降,甚至完全失效的故障也是有的。例如,无休止的线程、无释放的文件锁闭、数据污染、存储空间的彻底分裂与积聚差错等;
(2) 硬件可靠性的决定因素是时间,受设计、生产、运用的所有过程影响,软件可靠性的决定因素是与输入数据有关的软件差错,是输入数据和程序内部状态的函数,更多地决定于人;
(3)硬件的纠错维护可通过修复或更换失效的系统重新恢复功能,软件只有通过重设计或排除错误;
(4)对硬件可采用预防性维护技术预防故障,采用断开失效部件的办法诊断故障,而软件则不能采用这些技术;
(5)可靠性预测和可靠性增长等技术对软件和硬件有不同的意义;
(6)为提高硬件可靠性可采用冗余技术,而同一软件的冗余不能提高可靠性;
(7)硬件可靠性检验方法已建立,并已标准化且有一整套完整的理论,而软件可靠性验证方法仍未建立,更没有完整的理论体系;
(8)硬件可靠性已有成熟的产品市场,而软件产品市场还很新;
(9)软件错误是永恒的,可重现的,而一些瞬间的硬件错误可能会被误认为是软件错误。
从上我们看到,由于软件固有的特性,软件可靠性很难以硬件可靠性的概念为基础,来进行度量和评估,即硬件的可靠性计算方法和相关模型难以用于软件可靠性的估算中。这也正是软件可靠性评估与验证没有很好的方法、模型和技术,人们无法事先预测软件可靠性,无法确定软件可靠性是否增长的根本原因。
2、软件可靠性测试
从软件可靠性的定义上看,评价或测试一个软件的可靠性,最主要的是要确定系统怎样输入、如何使用一整套的方法和策略。即软件可靠性测试是指为了达到或验证用户对软件的可靠性要求而对软件进行的测试,属于软件测试或软件可靠性评价的范畴。尽管软件可靠性测试也不能保证软件中残存的错误数达到最少,但经过软件可靠性测试可以保证软件的可靠性达到较高的要求。
软件可靠性测试是在软件的预期使用环境中,为了最终评价软件系统的可靠性而运用建模、统计、试验、分析、评价等一系列手段对软件系统实施的一种测试。它应该是面向故障的测试,以用户将要使用的方式来进行的,每一次测试代表用户将要完成的一组操作,使测试成为最终产品使用的预演。如:我们可以通过给系统加载一定的业务压力(例如资源在70%~90%的使用率)的情况下,让应用持续运行一段时间,测试系统在这种条件下是否能够稳定运行。这里的可靠性测试仅仅是让软件在大压力环境下运行较长的时间,来估算系统是否能在平均压力下持续正常工作。
软件可靠性测试是获取软件可靠性估算数据的重要手段,它通过发现软件系统可靠性缺陷,为软件的使用和维护提供数据,确认软件是否达到可靠性的定量要求。目前软件可靠性测试用得最多的方法是类似于硬件操作剖面上的统计测试方法,即基于被测软件操作剖面的统计测试方法。这是最为传统、经典的软件可靠性测试方法。通过这种方法,能够实现软件可靠性的定量评估,从而有效地保障和提高软件的质量。
软件可靠性测试与传统意义上的软件测试不同,软件可靠性测试是统计测试思想在软件可靠性度量上的应用,要求测试按照软件的操作剖面进行,测试结果使用软件可靠性模型进行评价,其中操作剖面的构造是进行软件可靠性测试的基础。
操作剖面的英文是Operational Profile,也称为软件的使用模型,是指系统测试数据输入域以及各种输入数据的组合使用概率。它刻画了在预期环境中软件各种预期操作的统计分布,用来描述软件的实际使用情况的。在基于软件操作剖面的统计测试中,能够保证在测试过程中较早地发现那些在软件操作使用中最经常发生的失效。
操作剖面反映了软件规格说明定义的预期使用情况。因此在建立操作剖面之前,首先必须对规格说明进行评审和澄清,保证规格说明提供了完整的功能规格说明,描述了软件在预定环境中的预期使用情况;然后,根据用户使用这些系统模式、功能、任务的概率对软件的系统模式、功能、任务需求及相应的输入激励的分析来构造操作剖面。操作剖面构造的质量决定着其测试或分析结果是否可信的程度。
统计测试的英文是statistical testing;是通过使用对输入统计分布进行分析来构造测试用例的一种测试设计方法。
统计测试标识出频繁执行的部分,并相应地调整测试策略,针对这些频繁执行的部分进行详尽的测试。通过提高关键模块的安全性和可靠性,来提高整个系统的安全性和可靠性,以提高测试的性价比。统计测试进行的前提条件就是生成如实反映系统使用情况的使用模型。以往使用模型的建立主要是通过预测和估计得出的,不能如实地反映系统的真实情况。
通过软件可靠性测试可以有效地发现程序中影响软件可靠性的缺陷,从而实现可靠性增长。由于软件可靠性很大程度上依赖条件的变化,特别是软件操作剖面的输入分布。因此,我们首先需要建立描述软件操作情况的操作剖面,然后在软件的操作剖面基础上按照概率统计方法设计输入的分布,最后利用操作剖面从所有软件操作中获得统计上正确的采样并对软件进行可靠性测试。这种测试方法也是惟一能直接对软件操作可靠性进行估算的统计方法。通过操作建模可以改进规格说明,得到规格说明的分析性描述,量化测试代价,通过统计测试为软件可靠性推断提供依据。
事实上,软件可靠性测试方法就是一种黑盒测试方法,它面向需求、面向使用开展测试,不用了解程序的结构、程序的实现等问题。软件可靠性测试最好由独立的第三方测试机构来承担,主要是在系统测试、验收、交付阶段进行。
总之,基于被测软件操作剖面的统计测试方法是在对软件的实际使用情况进行统计的基础上建立软件的操作剖面,并采用统计测试的方法进行测试。用这种方法所获得的测试数据与软件的实际运行数据比较接近,可直接用于软件可靠性估算。
3、基于操作剖面的软件可靠性压力测试
前述的软件可靠性测试是基于被测软件操作剖面的统计测试方法,这种方法在操作剖面确定后如何针对由于长期使用软件性能下降,甚至完全失效这种严重影响软件可靠性的问题上有一定的不足。例如,无休止的线程、无释放的文件锁闭、数据污染、存储空间的彻底分裂与积聚差错等。而这些问题的产生还是软件设计和逻辑实现带来的问题。如果这些问题解决了,就不会出现由于长期使用使软件性能下降的问题。而解决这一问题的有效方法就是基于操作剖面的压力测试或疲劳测试,即在一段时间内(经验上一般是连续72 小时)保持操作剖面上的某些点进行某些操作频繁使用,检查系统是否发生功能或者性能上的问题。
通常现代大型软件的操作剖面很复杂,覆盖整个操作剖面进行压力测试是不现实的。如何在被测软件的操作剖面上确定压力测试的范围或测试点以及压力测试的类型是软件可靠性压力测试的重要研究内容。因此,在传统的操作剖面上结合软件可靠性统计测试方法,针对软件有别于硬件的自身特性,以及软件由于长期使用使软件性能下降,甚至完全失效这种严重影响软件可靠性的问题,采用操作剖面压力测试的方法,确定重要的压力测试点,并在这些压力测试点上分别进行相应类型的压力测试,以保证软件经过长时间运行后,性能不会下降,失效不会产生,来达到提高软件可靠性的目的。这种面点结合、互相补充的测试思想丰富了软件可靠性测试内容,解决了软件可靠性测试不仅要考虑操作剖面的功能统计测试问题,还要考虑操作剖面上的压力测试问题,并使操作剖面和操作剖面上的压力测试点成为相辅相成的软件可靠性测试方案。
从以上方案可以看到,准确地寻找操作剖面上的各个压力测试点,有效地确定压力测试类型,设计相应的压力测试用例,并将这些测试用例纳入到被测软件的操作剖面的统计测试用例中是软件可靠性压力测试的关键,也是现代软件可靠性测试的关键。这需要在操作剖面的基础上对被测软件进行静态分析和动态测试,查找可能严重影响软件可靠性的因素,如:内存泄露、数据污染、线程死锁、文件冲突等,并将这些作为压力测试点的压力测试内容,确定相应的压力测试类型。
由于软件自身的特点,软件可靠性与硬件可靠性相比内涵发生了根本的变化,软件可靠性估算必须以软件可靠性分析及软件可靠性测试等结果或缺陷数据为重要依据,软件可靠性估算模型及模型输入参数与软件可靠性测试结果紧密相连。为此,我们一定要抓住软件的特性,强调软件可靠性测试对于软件可靠性估算的重要支撑作用,研究软件可靠性测试方法和技术,特别是研究基于被测软件操作剖面的压力测试技术和基于软件可靠性分析和测试结果的软件可靠性估算模型是一个有理论价值和变革意义、并存在很大的难度且面临极大挑战的研究课题,这也是本文抛砖引玉要达到的目的。
4、结束语
本文对软件的自身特性、软件可靠性及软件可靠性测试等概念进行了阐述,并在此基础上根据笔者工作实践对软件可靠性测试方法进行了探讨,提出了用操作剖面上的压力测试概念来弥补传统的操作剖面上的功能统计测试的不足,强调软件可靠性测试对于软件可靠性估算的重要支撑作用。软件可靠性研究的理论和方法多种多样但无法实施和运用的关键问题是没有很好地分析和研究软件的自身特性和软件出错的自身规律,照搬照套硬件可靠性的概念和估算方法与估算模型,从而使软件可靠性估算及评测走向死胡洞。对软件可靠性估算及评测起决定支撑作用的软件可靠性测试应该是当前乃至今后的一个重要研究领域或课题。计算机系统或软件系统的整个可靠性应该分别计算硬件可靠性和软件可靠性,然后进行结果的科学整合,而这也是国内外研究的空白,因此需要有更多的人力和物力投入到这方面的研究之中。
摘要:软件测试在软件开发中占有非常突出的重要位置,软件必须通过测试才能确保其在应用环境中正常工作。在测试过程,运用自动化软件测试技术可以减少测试周期,节约人力成本,同时也减少了人为出错的机率。
本文通过对自动化测试技术的介绍,对当前流行的几种自动化测试技术以及自动化测试工具的比较,系统全面的讨论了自动化测试技术。首先从介绍自动化测试的基本概念入手,然后对当前几种比较流行的自动化测试技术进行了研究和比较,接着介绍了几款成熟的自动化测试工具,最后对自动化测试进行了总结和展望。
关键词:自动化测试;手动测试;测试用例;测试工具;
一、前言
软件测试是对创造力和智力非常有挑战性的任务。测试一个大型软件需要的智能要超过设计这个程序的智能。 软件在它发行之前应当通过彻底的测试以保证它的可靠性和功能性。测试工程师要覆盖一个大型应用程序的所有情况是一件非常麻烦和费时的事情,但为了保证软件质量,我们不得不这样做。那么有没有省时省力的技术或者工具去帮我们做这样的事情呢,由此便有了下面对于自动化测试技术的探讨。
二、自动化测试的概念
自动化测试一般是指软件测试的自动化,软件测试就是在预设条件下运行系统或应用程序,评估运行结果,预先条件应包括正常条件和异常条件。
自动化测试一般包括测试过程自动化和测试结果分析自动化。测试过程的自动化指的是不用手工逐个的对用例进行测试。测试结果分析自动化指的是不用人工一点点去分析测试过程中的中间结果或数据流。
软件自动化测试就是模拟手动测试步骤,执行用某种程序设计语言编制的测试程序,控制被测软件的执行,完成全自动或半自动测试的过程。全自动测试就是指在自动测试过程中,根本不需要人工干预,由程序自动完成测试的全过程。半自动测试就是指在自动测试过程中,需要手动输入测试用例或选择测试路径,再由自动测试程序按照人工指定的要求完成自动测试。
三、自动化测试的前提
对于开发出来的软件产品,是不是都可以使用自动化测试技术,这个答案显然是否定的,对于是否应用自动化测试技术我们需要一定的前提条件。
1)软件需求变动不频繁。
测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁,测试人员需要根据变动的需 求来更新测试用例以及相关的测试脚本,而脚本的维护本身就是一个代码开发的过程,需要修改、调试,必要的时候还要修改自动化测试的框架,如果所花费的成本 不低于利用其节省的测试成本,那么自动化测试便是失败的。项目中的某些模块相对稳定,而某些模块需求变动性很大。我们便可对相对稳定的模块进行自动化测试,而变动较大的仍是用手工测试。
2)项目周期足够长。
由于自动化测试需求的确定、自动化测试框架的设计、测试脚本的编写与调试均需要相当长的时间来完成。这样的过程本身就是一个测试软件的开发过程,需要较长的时间来完成。如果项目的周期比较短,没有足够的时间去支持这样一个过程,那么自动化测试便成为笑谈。
3)自动化测试脚本可重复使用。
如果费尽心思开发了一套近乎完美的自动化测试脚本,但是脚本的重复使用率很低,致使其间所耗费的成本大于所创造的经济价值,自动化测试便成为了测试人员的练手之作,而并非是真正可产生效益的测试手段了。
另外,在手工测试无法完成,需要投入大量时间与人力时也需要考虑引入自动化测试。比如性能测试、配置测试、大数据量输入测试等。
四、自动化测试与手动测试
自动化测试相对于手工测试的优点:
● 优化测试速度:可非常快速的运行上万条记录
● 提高准确性、稳定性:可以不为外界因素干扰,准确运行测试用例
● 确定性:能真实快速搭建测试环境,测试数据,重现缺陷
● 提高工作效率:一边运行自动化测试,一边准备测试报告
● 测试环境搭建:可以结合多种编程语言及技术协助搭建测试环境,防止手工测试重复劳动,如批处理技术
● 提高技能:可提高测试人员技能,同时提高对测试的兴趣,防止对手工测试感觉枯燥
但是对于自动化测试也不要进入一个误区,有自动化测试不再需要手工测试这种观点是不对的。自动化测试虽然有如此多的优点,但是有些测试比如:本地化测试、用户体验测试、测试环境搭建方面并不能完全代替手工测试。自动化测试的基础也必须是对产品的运行,测试点有一定的手工测试的基础,自动化测试和手动测试是相辅相成的。自动化测试并不仅指自动化运行测试产品,数据处理也是非常重要的一个环节。并非只是自动化测试工具如QTP,Loadrunner,等才可以做自动化测试,很多的编程语言都可以运行自动化测试。比如QTP就是基于VBScript语言的一款自动化测试工具,只是在VBS上的一些封装。
五、自动化测试技术比较
● 基于组件的自动化测试技术
该测试是针对软件设计的最小单位——组件,进行正确性检验的测试工作.其目的在于发现各组件内部可能存在的各种差错,确保每个组件都能有效实现自己的预期功能。这一步是为了在选择组件阶段把好组件“准人”关,无论是自己开发组件、第三方组件或是其它来源的组件,都要对每一个组件进行测试。组件自身测试是典型的黑盒测试,即在不考虑代码内部结构的前提下,根据需求对应用程序进行测试。它的任务足验证组件的功能及其它特征是否与预期的要求一致。组件测试时应充分考虑到该组件可能涉及到的尽可能多的内外环境因素。

基于组件的自动化测试技术的过程模型
● 基于关键字驱动的自动化测试技术
在我们的测试脚本中可能会用到上千条这样的语句,测试工具通过按钮名字和显示文本来识别这个按钮。可以想见,当其中任何一个发生改变时,所有相关的脚本都会受到影响,维护这样的脚本是十分困难的。为解决该问题,我们可以做到以下几个分离,界面元素名与测试内部对象名的分离,测试描述与具体实现细节的分离,脚本与数据的分离。以上这“三个分离”正是关键字驱动自动化测试的核心思想,各司其职、互相独立,才能最大程度地减少相互之间的影响。

基于关键字的自动化测试模型
● 基于数据操作的自动化测试技术
所谓数据操作操作自动化测试技术,就是把数据作为测试动作应用的基本对象,并以此为出发点,把对数据驱动的软件测试活动转化为一系列数据操作,通过不同的数据操作体现被测软件的应激状态,进而达到软件测试的目的。从上文可知,关键字驱动脚本通过导航脚本控制,分别读取关键字支持脚本和数据文件的固有机制带来了执行效率问题,因此可以合并导航脚本和关键字支持脚本,即提高关键字脚本所处的层次,也就是说,把脚本执行控制字和数据操作关键字合并,形成一种真正的面向数据操作的脚本语言,同时为了解决文件数据固定问题,使用另一种脚本来描述多样的数据结构,同时把对数据的不同加工方式融入脚本描述中,这样就解决了数据结构定制和完备产生的困难。
● 基于模型驱动的自动化测试技术
模型驱动测试就是通过对SUT的功能与系统结构进行分析,然后结合测试策略构建起全面、清晰的测试模型,最后通过测试模型自动生成测试用例驱动测试人员完成SUT的测试。模型驱动测试的优点主要有两方面:
(1)测试模型为用户提供了更加清晰、准确和系统的测试设计。无论是基于数据驱动的还是基于关键字驱动的自动化测试技术展现给用户的都是一个个互不相关的测试用例啪,用户很难从生成的测试用例中理解整个测试系统的结构与测试重点。
(2)减少了测试用例维护工作,实现了测试资源的重利用,有效缩短了测试周期。建立起测试模型后,测试系统没计师可以在测试需求或SUT的系统设计规格发生改变后通过调整测试模型(而不是个性测试用例)来适应变化。

基于模型驱动的自动化测试架构图
● 基于数据驱动的自动化测试技术
数据驱动自动化测试是一种数据被包含在输入测试数据文件中,并且以数据来控制自动化测试脚本执行的流程和动作的测试。输入测试数据记录是从外部文件中读入的,并且是独立于测试脚本程序开发的。数据驱动测试使用存档的测试数据来驱动自动化测试过程,这些数据通常以简单的文本文件或Excel文件(电子表格)形式存在。

基于数据驱动的自动化测试框架图
六、自动化测试工具介绍
随着计算机应用的日益普及和深化,现代软件的规模越来越大、类型越来越复杂。设计人员和使用人员都希望在将软件系统投入运行之前,能尽可能地提高软件的质量。软件测试对确保软件质量有着极其重要的作用,但是手工的测试工作是非常繁琐和低效率的,为了更有效的进行软件测试,让一部分工作利用自动化工具进行自动测试是非常有效的方法。下面为几款具有代表性的自动化测试工具。
Rational Robot
是业界最顶尖的功能测试工具,它甚至可以在测试人员学习高级脚本技术之前帮助其进行成功的测试。它集成在测试人员的桌面IBM Rational Test Manager上,在这里测试人员可以计划、组织、执行、管理和报告所有测试活动,包括手动测试报告。这种测试和管理的双重功能是自动化测试的理想开始。
Win Runner
是一种企业级的用于检验应用程序是否如期运行的功能性测试工具。通过自动捕获,检测,和重复用户交互的操作,Win Runner能够辨认缺陷并且确保那些跨越多个应用程序和数据库的业务流程在初次发布就能避免出现故障,并且保持长期可靠运行。
QuickTest Professional
是一个功能测试自动化工具,主要应用在回归测试中。QuickTest针对的是GUI应用程序,包括传统的Windows应用程序,以及现在越来越流行的Web应用。它可以覆盖绝大多数的软件开发技术,简单高效,并具备测试用例可重用的特点。其中包括:创建测试、插入检查点、检验数据、增强测试、运行测试、分析结果和维护测试等方面。
AdventNet QEngine
AdventNet QEngine是一个应用广泛且独立于平台的自动化软件测试工具,可用于Web功能测试、web性能测试、Java应用功能测试、Java API测试、SOAP测试、回归测试和Java应用性能测试。支持对于使用HTML、JSP、ASP、.NET、PHP、JavaScript/VBScript、XML、SOAP、WSDL、e-commerce、传统客户端/服务器等开发的应用程序进行测试。此工具以Java开发,因此便于移植和提供多平台支持。
SilkTest
是业界领先的、用于对企业级应用进行功能测试的产品,可用于测试Web、Java或是传统的C/S结构。SilkTest提供了许多功能,使用户能够高效率地进行软件自动化测试。这些功能包括:测试的计划和管理;直接的数据库访问及校验;灵活、强大的4Test脚本语言,内置的恢复系统(Recovery System);以及具有使用同一套脚本进行跨平台、跨浏览器和技术进行测试的能力。
QA Run
QARun的测试实现方式是通过鼠标移动、键盘点击操作被测应用,即而得到相应的测试脚本,对该脚本可以进行编辑和调试。在记录的过程中可针对被测应用中所包含的功能 点进行基线值的建立,换句话说就是在插入检查点的同时建立期望值。在这里检查点是目标系统的一个特殊方面在一特定点的期望状态。通常,检查点在QARun提示目标系统执行一系列事件之后被执行。检查点用于确定实际结果与期望结果是否相同。
Test Partner
是一个自动化的功能测试工具,它专为测试基于微软、Java和Web技术的复杂应用而设计。它使测试人员和开发人员都可以使用可视的脚本编制和自动向导来生成可重复的测试,用户可以调用VBA的所有功能,并进行任何水平层次和细节的测试。TestPartner的脚本开发采用通用的、分层的方式来进行。没有编程知识的测试人员也可以通过TestPartner的可视化导航器来快速创建测试并执行。通过可视的导航器录制并回放测试,每一个测试都将被展示为树状结构,以清楚地显现测试通过应用的路径。
Telelogic TAU
TAU第二代包含三个最新的、最强大的技术用来加速大规模软件开发和测试:统一建模语言(UML)及它的许多最新修订版本中的特性,UML2.0;功能强大的测试语言TTCN-3和新的构造系统的方法:Model Driven Architecture(模型驱动构架)。这三个新的业界标准结合成TAU的已经过认可的软件开发平台,形成了一个系统,一个一流的稳定可靠的工具解决方案。TAU第二代是系统与软件开发解决方案的一个突破,它把业界从使用了太长时间的手工、易出错、以代码为中心的方法中释放出来,自然而然地迈向下一步,一个更加可视化、自动化及可靠的开发方法。
Telelogic TAU/Tester是基于通用测试语言TTCN-3,用于自动化的系统和集成测试的强大工具。TAU/Tester以现代化的开发工具为基础,提供高层测试功能,支持整个测试生命周期,加速自动化测试。TAU/Tester可使用户特别关注于测试的开发,因为TTCN-3语言是独立于开发语言或测试设备的,且是抽象和可移植的。
七、总结
通过研究和比较当前比较流行的几种自动化测试技术,我们可以对自动化测试技术发展方向做出以下展望。
采用标准化架构
在企业产品线日益膨胀的情况下,采用一个标准化架构开发通用测试平台是行之有效的方法,以提高产品从研发到生产测试的整个生命周期里测试硬件和软件组件的复用性。
多通道RF测试
无线技术变革已经对测量测试行业产生巨大影响,其中两个关键技术趋势尤为突出,其一是MIMO技术,其二便是多种无线标准在同一系统中的集成。这两个技术趋势都要求射频测量系统能够实现并行测试,这就需要可配置的多通道射频测试系统。
Peer-to-Peer高速传输与计算
随着测试需求的日益复杂和数据量的指数态增长,自动化测试系统需要更强的处理能力,分布式处理的架构也随之被提出。新一代高性能分布式架构应以下具有高吞吐量点对点拓扑结构、低延迟、能够提供用户自定义处理节点这三大特性。
摘要:在软件测试技术的不断发展过程中,自动化测试技术作为软件测试技术的一个分支,被越来越多的使用在软件测试的各个阶段,大大节省了软件测试成本、提高了测试效率、缩短了软件开发周期。本文结合自动化测试理论与技术,基于现有的自动化测试技术、测试框架以及自动化测试工具进行了研究,提出了一种基于当前较成熟的软件测试自动化技术一关键字驱动的自动化测试技术而构建的自动化测试框架模型,并在此框架模型的基础上,设计实现了基于Selenium 的自动化测试框架。
关键词:自动化测试;Selenium;测试框架
0、引言
在现代化管理中,如优化问题、信息系统、决策支持系统等,都要广泛地应用软件。软件质量的优劣是通过对软件的功能、性能和可靠性等质量要素进行验证的,发现软件缺陷并帮助定位和修复缺陷,确保软件系统功能满足需求的活动。根据多年软件工程研究和实践经验,认为通过在软件项目中执行如下最佳经验,可以有效提高软件质量,确保项目进度:
a)强化开发人员测试;
b)尽早引入性能测试;
c)实施测试管理自动化;
d)引人功能测试执行自动化。
可以说,实施测试自动化是软件行业一个不可逆转的趋势,如果在这个领域走在了前列,无论从企业的核心竞争力还是个人的工作技能来说,都有巨大的优越性。
自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常,在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的规程一步步执行测试,得到实际结果与期望结果的比较。在此过程中,为了节省人力、时间或硬件资源,提高测试效率,便引入了自动化测试的概念。相对于手工测试而言,测试自动化通常具有速度快、执行效率高、测试全面,可连续工作,执行过程受外界因素干扰小、测试结果准确等优点。缺点是前期投入较大,所以在采用测试自动化之前需做好相应的评估工作。本文以Selenium 自动化测试框架为应用背景,对测试自动化在系统测试过程中的应用做了初步的研究。
1、软件测试的优化分析
随着人们对软件质量重视程度的提高,软件测试的地位逐步提高,软件测试技术也随之快速发展,逐渐从过去手工式的测试向测试自动化方向发展,引发了软件测试自动化的研究和应用热潮。目前,软件测试自动化的研究领域主要集中在软件测试流程的自动化管理以及动态测试的自动化(如单元测试、功能测试以及性能测试方面)。在这两个领域,与手工测试相比,测试自动化的优势是明显的。首先,自动化测试可以提高测试效率,使测试人员更加专注于新的测试模块的建立和开发,从而提高测试覆盖率;其次,自动化测试更便于测试资产的数字化管理,使得测试资产在整个测试生命周期内可以得到复用,这个特点在功能测试和回归测试中尤其具有意义;此外,测试流程自动化管理可以使机构的测试活动开展更加过程化,这很符合CMMI过程改进的思想。根据Oppenheimer Funds的调查,在2001年前后的3年中,全球范围内由于采用了测试自动化手段所实现的投资回报率高达1500%。
然而,存在优势并不一定意味着选择自动化测试方案都能为企业带来效益汇报,在决定是否引人自动化测试或使用合适的自动化测试方案以前,需从以下方面进行分析:
(1)选择合适的自动化测试方案测试自动化的引进和实施,不仅涉及测试工作本身流程上、组织结构上的调整与改进,甚至也包括需求、设计、开发、维护及配置管理等其他方面的配合。如果对这些必要的因素没有考虑周全的话,必然在实施过程中处处碰壁,既定的实施方案也无法开展。
(2)尽管自动化测试可以降低人工测试的工作量,但并不能完全取代手工测试。100% 的自动化测试只是一个理想目标,即便一些如SAP、Oracle ERP等测试库规划十分完善的套件,其测试自动化率也不会超过70% 。所以一味追求测试自动化只会给企业带来运作成本的急剧上升。再次,实施测试自动化需要企业有相对规模的投入,对企业运作来说,投入回报率将是决定是否实施软件测试自动化的最终指挥棒,因此企业在决定实施软件测试自动化之前,必须要做量化的投资回报分析。
(3)实施软件测试自动化并不意味着必须采购强大的自动化软件测试工具或自动化管理平台,在企业内部通常存在许多不同种类的应用平台,应用开发技术也不尽相同,甚至在一个应用中可能就跨越了多种平台,或同~应用的不同版本之间存在技术差异。所以选择软件测试自动化方案必须深刻理解这一选择可能带来的变动、来自诸多方面的风险和成本开销。毕竟软件质量的保证不是依靠产品或技术,更多的因素在于高素质的人员和合理有效的流程。
2、选型分析
实施自动化测试之前需要对软件开发过程进行分析,以观察其是否适合使用自动化测试。通常需要同时满足以下条件:
1)软件需求变动不频繁
测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁,测试人员需要根据变动的需求来更新测试用例以及相关的测试脚本,而脚本的维护本身就是一个代码开发的过程,需要修改、调试,必要的时候还要修改自动化测试的框架,如果所花费的成本不低于利用其节省的测试成本,那么
自动化测试便是失败的。
项目中的某些模块相对稳定,而某些模块需求变动性很大,此时可对相对稳定的模块进行自动化测试,而变动较大的仍是用手工测试。
2)项目周期足够长
由于自动化测试需求的确定、自动化测试框架的设计、测试脚本的编写与调试均需要相当长的时间来完成。这样的过程本身就是一个测试软件的开发过程,需要较长的时间来完成。如果项目的周期比较短,没有足够的时间去支持这样一个过程,那么实施自动化测试就变成空谈。
基于上述条件,我们在实际应用中多选取在项目规模较大的回归测试环节,或者增量式开发、持续集成的项目中采用自动化测试。
3、测试框架评估
自动化测试框架从最初简单的脚本录制/回放发展到结构化脚本、数据驱动?(data·driven)脚本,再发展到关键字驱动(keyword.driven)脚本,以及相继出现的各种自动化测试框架,逐渐形成了良好的脚本开发环境或平台,使得自动化测试脚本的开发更具开放性、可视性和层次性,测试人员开发和维护脚本都变得更轻松、容易,从而在整体上进一步提高自动化测试的效率和应用范围。
现有可提供自动化测试解决方案的产品很多,但是其应用结果往往不竞如人意,主要存在:定位控件不方便;验证数据不方便;代码维护不方便等。对于经常涉及手工任务操作的Web应用程序测试,为了尽可能地消除人为因素,节约手工操作的人员成本和时间,实现跨平台的Web测试框架,我们发现了Selenium这个开源的软件自动化测试框架。
a)自动化框架的选择
测试框架的选择是成功实施测试自动化的基础,必须考虑各种因素以使测试自动化更加有效地被使用。Selenium是一种Web应用的自动测试工具,通过模拟用户对Web页面的各种操作,可以精确重现软件测试人员编写的Test Cases步骤。相对于一般的脚本录制自动化框架,其优势在于:
(1)Selenium测试直接在浏览器中运行,就像真实用户所做的一样。Selenium测试可以在Windows、Linux和MacintoshAnd上的Internet Explorer、Mozilla和Firefox中运行。其他测试工具都不能覆盖如此多的平台。
(2)Selenium提供了组件化的测试用例开发方法,建立了灵活的表达方式,很大程度了提高了运行脚本的复用率,节省了脚步开发时间。
(3)通过Selenium开发的自动测试框架,对组件进行了有效封装,大大降低了维护工作量。不会产生传统自动化测试工具录制回放方法中出现的随程序变更,需要重复录制脚本的问题。
(4)Selenium以业务为驱动,可以通过测试数据流的配置,快速、灵活地实现不同的业务流分支的回归测试。
(5)Selenium的测试用例、测试结果数据统一在配置库中管理,实现了测试工具无关性。可以很好的进行移植,并为用户提供了一套完整的测试资产库。
但是Selenium是轻量的测试框架,脚本所处理的测试用例构成简单,其实质就是通过HTTP协议,发送请求(request)来完成测试用例,所以很困难处理业务逻辑关系强的测试用例。

b)选择合适的测试用例
大部分自动化测试项目失败的原因主要归咎于被测试应用程序的快速变化、不恰当的测试用例、不可靠的框架、脚本编程等问题。并非所有的测试用例都可以用自动化来完成,因此需要对用例进行挑选,选择合适的用例作为自动化测试用例。自动化测试的成本是巨大的,一般来说,一个脚本运行6—7次才算收回成本,因此不可寄予自动化测试过高期望。通常需要结合测试用例的复杂度的评估来考虑选择的测试用例以及个数。这样会带来较低的维护成本,实现更重要的业务价值。
首先把测试用例按一定的原则分为简单、中等、复杂3大类。然后从这3大类的测试用例中按一定的比例来抽取需要实现自动化的用例。测试用例的复杂度分组可以通过综合分析测试用例包含的操作步骤,以及测试用例所包含的检查点个数来判定。
c)基于Selenium的分层测试框架
在Selenium环境中组织多个测试模块的测试,每个模块实现特有的功能,有多条测试路径需要覆盖,同时,各个模块功能之间又有共通之处,可以抽取某些部分进行复用。对此,我们假设这样的场景:分别对提交的多个待测组件返回的结果页面中设置相应的检查点,为它们撰写Test Cases用于执行测试。事实上,这些组件的测试由于同质性,还能够合并为一种测试,用不同的输入参数来指定所要测试的那个待测组件。
表中针对上述各待测组件做自动化测试,以一个经验丰富的测试人员做3次回归做一个成本对比。
通过上面表格的对比,可以很明显看出很多模块功能都包含一些公共检查点,例如:文本框、DBGrid列表信息、showModalDialog自定义控件、修改信息保存成功、树形节点、各种级别菜单选择等等。把这些公共检查点封装在公共函数库中,任何新功能模块的验证都只需要调用公共函数、配置测试数据,组合调试好测试脚本就可以进行测试了,这样大大提高了测试效率和测试覆盖率。
d)集成运行框架
构造一个适当的集成环境,会极大地提高自动化的效率。例如,通过数据库服务器来存储和管理测试用例和测试结果,以提高过程管理的质量。同时生成统计所需要的数据,供Web服务器使用,显示测试结果、生成统计报表、结果曲线。运行一个自动化测试项目时,客户端先通过Web服务器查询所用的测试用例和资源;然后提交任务,Web服务器负责向控制机发出指令,开始执行测试任务。测试结果经控制器存储到数据库中测试自动化运行环境,如图1所示。

图1 测试自动化的集成运行框架
e)脚本维护
测试脚本的开发和维护直接关系到软件测试自动化的成败,至少对自动化测试的投入产出存在巨大的影响。同时对不同的测试库的权限应该有很明确的定义。一个好的方案会将测试库的组织划分为三个级别:
级别1:全局的,这个一个通常的级别,被存储在这个级别的测试功能能够被所有的项目访问。通用的功能如,登陆、创建一个用户都是这个级别很好的候选者。
级别2:项目的,在这个级别的测试功能是与特定的测试项目相关的,但是通常在项目中有用的。通用的功能如,项目中自定义控件等。通常级别2是级别1的功能的提供者。
级别3:脚本的,功能被直接关联到特定的测试脚本。在这个级别中,通常一个测试功能的第一个版本是被开发的。在新的测试脚本的创建期间已有测试功能的重用性被发现,并被移到了级别2中。在这个级别上尽量最小化功能的数量,因为它将增加维护工作量。
4、结语
从软件测试的优化来看,如何实现软件的自动化测试是一个很吸引人的技术问题,由于不同企业在组织架构、人员能力以及管理水平等方面的不同,我们很难用一个实例、一两句话来说明不同解决方案的适用性,具体如何选择,需要仔细权衡。
实施测试过程改进的五个步骤
综合了组织需要进行的所有活动,测试过程改进的实施需要采取以下五个步骤(见图表1):
● 与发起人沟通并理解业务目标
● 通过审查和面谈来评估当前测试过程
● 报告评估结果并建立执行路线图
● 实施建议的改进措施
● 测量实施后的效果
第1步:与发起人沟通并理解业务目标
发起人是指分配测试过程改进项目的人,或倡导对测试过程进行评估的人,或签署测试过程咨询协议的人。开始测试过程评估的首要步骤是与测试过程评估的发起人沟通,详细了解组织的过程和业务目标。很多企业都认识到必须改进其测试过程,但是对如何改进以及改进的必要步骤却不是很清楚或者没有一个清晰地思路。经过与发起人的细致讨论,要为测试过程改进定义明确的目标。无论使用什么方式进行测试过程评估,首要考虑的因素都是建立评估的目标。评估的目标根据组织的类型及其需要会有所不同,一些例子如下:
● 减少测试费用
● 提高测试的有效性
● 提高测试的效率
● 提高组织总体的测试成熟度
● 提高测试收益的可见性。等等
在组织要求的基础上,我们必须制定明确的达成的目标,并将其作为测试过程评估的一部分。一旦确定了目标,接下来要做的事情是尽可能的将这些目标转化为度量指标和数字。使用明确直观的度量指标能够帮助企业度量他们的改进效果、认识到他们的位置并为该项目提供方向。作为测试过程改进的一部分,企业明确设定要达成的目标是至关重要的,同时整个改进过程基于目标而划分为多个阶段。
第2步:通过审查和面谈来评估当前测试过程:
执行评估方法的制定基于测试组织的业务目标与评估目标。通常有两类执行测试过程评估的方法:
1、正式的测试过程评估,这是相对有条理,结构化并往往消耗较多时间的。
2、非正式的、非结构化测试过程评估,这类的评估方法基于特定的需要,消耗较少的时间。

图表2 评估的输入和输出项
在组织中,测试通常不是孤立存在的,它与多个业务团队、开发团队、供应商、测试环境团队等共同存在。应首先确定所有主要的干系人(在组织中最能够影响测试团队或者最受测试团队影响的角色)。同时,应从已存在的项目中收集工件,并脱机检查这些工件。可以根据业务目标来准备一份调查问卷提供给干系人填写。当收到来自干系人的反馈后,则可以将这些内容与从项目工件中收集到的信息整合起来。
图2给出了测试过程评估的输入和输出项的图形表示。
在从文档检查和调查问卷中获得了必要的信息后,接下来需要准备一份面向每位干系人的访谈问题列表。应该与每位干系人进行访谈,访谈的焦点要集中于已发现的组织现状与干系人反馈之间的差异。在访谈中,应该设计更多关于测试组织、组织的测试策略、组织的测试过程、项目的测试过程和测试方法、测试管理和环境管理、测试审查和优化等内容的探索式问题,同时要收集关于待评审测试过程的更多信息。访谈问题的设计可以根据干系人在组织中的角色进行自定义。
随着对高效IT过程的需要、客户期望的提高和对高质量产品的关注,软件测试的重要性显得突出起来。出于对成本和质量的重视,大多数企业已经建立起基本的测试过程和测试团队,但是却面临其他挑战。许多企业虽然对测试进行大量投入,却不太能获得相应的收益;大多数同时负责开发和测试的CIO会觉得尽管在测试中进行了相当的投入,最终用户却经常抱怨在使用时有太多缺陷,或者他们觉得测试没有提升产品的质量。
今天,大多数企业都承认改善和建立高效的测试过程可以解决这些问题,但他们通常很难有效地定义自身当前的进程,也并不知道如何进行必要的改进。以下一些原因使得企业希望进行测试过程咨询:
● 即使建立了测试实践,企业依旧不能达到足够的测试覆盖率或者缺陷发现得太晚以致修正缺陷需要增加大量成本。因此,企业想要检查自身测试过程与行业标准的差距或依照其设定基准。
● 企业关注于提高测试水平,但却不知道如何提高。
● 一些组织想要从第三方处了解到他们的当前状况以及如何进行改善。
● 大多数干系人抱怨测试没有效果。
● 大多数消费者抱怨终端产品中的缺陷。
● 想要优化当前的测试过程。
● 当前测试团队不能提供预期的投资回报等。
企业不能从测试实践中获得收益的主要原因是,他们对当前测试过程的有效性和效率缺乏足够深入的认识。这表现在企业尽管实施了测试过程,他们仍然支出高额的运营费用、不能达到所要求的质量等级或者质量不能完全满足其业务目标。
一般情况下,企业面临各种测试问题且无法实现投资回报可能是由以下原因造成的:
● 测试过程与整个软件开发生命周期不符
● 测试活动仅在产品投入使用之前才开始进行,导致了大量的返工和费用的增加
● 软件测试专业知识的缺乏使得很多缺陷没有被发现
● 正在使用的测试过程适合当前需要,但可能不适合不断变化的业务需求
● 所使用测试方法与被测系统的测试重点和开发方法不匹配。
随着竞争的日益激烈和业务需求的不断变化,测试和测试过程需要在组织中持续地进行监控并进行相应的改进。测试过程改进能够识别出组织当前测试过程的强弱项,并根据实际情况提出必要的改进建议。基本上,所有的成熟度模型都包括了各类测试活动(测试策划、测试用例设计、缺陷管理等),并能够协助进行测试过程评估。
什么是测试过程评估?
测试过程评估是一种方法或服务,它能够使组织识别和定义出当前的测试过程、对这些过程进行分析并找出需要改进的区域。它包括对当前测试过程的评估,深入了解测试过程对开发项目的帮助以及测试过程是否被真正应用。它可以帮助组织清楚当前测试过程的成熟度水平,帮助深入了解当前成熟度的状态,以及提供针对质量和成本改善的改进建议。
测试过程评估也提供了实施改进建议的必要步骤。这样做是为了发现哪些过程适合企业的业务需要,而哪些不适合。不同类型的企业的测试过程表现出很大的不同,例如:有的大型企业已经遵循了业界广泛认可的成熟度模型(如TPI或TMMi),而有的小型企业可能还没有建立适当的测试实践。在小型企业或小型企业的决策者中可能存在着这样的一种意识:测试过程改进只(更)适用于大型企业。事实上,测试过程改善适用于在测试上进行投入的所有企业,并对所有企业都一样重要,无论是大型的还是小型的。

实施测试过程改进的五个步骤
综合了组织需要进行的所有活动,测试过程改进的实施需要采取以下五个步骤(见图表1):
● 与发起人沟通并理解业务目标
● 通过审查和面谈来评估当前测试过程
● 报告评估结果并建立执行路线图
● 实施建议的改进措施
● 测量实施后的效果
第1步:与发起人沟通并理解业务目标
发起人是指分配测试过程改进项目的人,或倡导对测试过程进行评估的人,或签署测试过程咨询协议的人。开始测试过程评估的首要步骤是与测试过程评估的发起人沟通,详细了解组织的过程和业务目标。很多企业都认识到必须改进其测试过程,但是对如何改进以及改进的必要步骤却不是很清楚或者没有一个清晰地思路。经过与发起人的细致讨论,要为测试过程改进定义明确的目标。无论使用什么方式进行测试过程评估,首要考虑的因素都是建立评估的目标。评估的目标根据组织的类型及其需要会有所不同,一些例子如下:
● 减少测试费用
● 提高测试的有效性
● 提高测试的效率
● 提高组织总体的测试成熟度
● 提高测试收益的可见性。等等
在组织要求的基础上,我们必须制定明确的达成的目标,并将其作为测试过程评估的一部分。一旦确定了目标,接下来要做的事情是尽可能的将这些目标转化为度量指标和数字。使用明确直观的度量指标能够帮助企业度量他们的改进效果、认识到他们的位置并为该项目提供方向。作为测试过程改进的一部分,企业明确设定要达成的目标是至关重要的,同时整个改进过程基于目标而划分为多个阶段。
第2步:通过审查和面谈来评估当前测试过程:
执行评估方法的制定基于测试组织的业务目标与评估目标。通常有两类执行测试过程评估的方法:
1、正式的测试过程评估,这是相对有条理,结构化并往往消耗较多时间的。
2、非正式的、非结构化测试过程评估,这类的评估方法基于特定的需要,消耗较少的时间。

图表2 评估的输入和输出项
在组织中,测试通常不是孤立存在的,它与多个业务团队、开发团队、供应商、测试环境团队等共同存在。应首先确定所有主要的干系人(在组织中最能够影响测试团队或者最受测试团队影响的角色)。同时,应从已存在的项目中收集工件,并脱机检查这些工件。可以根据业务目标来准备一份调查问卷提供给干系人填写。当收到来自干系人的反馈后,则可以将这些内容与从项目工件中收集到的信息整合起来。
图2给出了测试过程评估的输入和输出项的图形表示。
在从文档检查和调查问卷中获得了必要的信息后,接下来需要准备一份面向每位干系人的访谈问题列表。应该与每位干系人进行访谈,访谈的焦点要集中于已发现的组织现状与干系人反馈之间的差异。在访谈中,应该设计更多关于测试组织、组织的测试策略、组织的测试过程、项目的测试过程和测试方法、测试管理和环境管理、测试审查和优化等内容的探索式问题,同时要收集关于待评审测试过程的更多信息。访谈问题的设计可以根据干系人在组织中的角色进行自定义。
图表1 测试过程改善的五个步骤
第3步:报告评估结果并建立执行路线图:
通过从不同领域和不同干系人收集来的数据,我们可以对组织的当前过程、能力和他们想要达成的目标有了清楚的认识。改善措施要建立在组织需要的基础上。例如,有些过程可能成熟度并不高,但是由于它们对组织的目标没有任何影响,所以可以忽略。
对所有相关因素加以考虑有助于推荐出一套可以立即实施于组织中几个项目团队的必要改进措施和度量指标。
改进建议可进一步分为短期、中期和长期实施措施。
第4步:执行建议的改进措施:
在建立了基于业务和组织的测试目标的必要改进措施后,下一步行动包括对改善措施排序优先级,即明确出希望哪些改善措施能够立即实施以速见成效、希望哪些改善措施过段时间后再实施,以及他们要如何实施这些改善措施。优先级的排序可以考虑如下一些参数:每个改善措施需要的时间、必要的投入(人力、软件、硬件)、实施改变的困难度、每个改善措施对测试过程分别的影响等等。基于如上的参数,可以给测试过程改进发起人提供一份改善措施优先级的列表。
通常情况下,改善项目可以分为短期(0-3个月)、中期(4-6个月)和长期(达1年)。应该建立改善项目的计划,并与组织就他们想要做什么、希望如何去做达成一致。
第5步:测量实施后的效果:
一旦实施了测试过程改进,改进团队应该定期从各位干系人处收集反馈信息。分析收集到的反馈信息以了解改进的效果并识别出进一步的调整。
形成通过实施改进取得收益的详细报告,并提交给主要负责人和其他干系人。
实施测试过程改进中的最佳实践
测试过程改进应以循序渐进的方式进行,希望采用一步到位的方法来实现过程改进是不正确的。一些准则有助于成功的实施测试过程改进:不要尝试太多改变而是实施几个有意义的改变来推动组织向前发展;分析优先级高的域并处理它们;针对能产生较大影响的域进行改变。首先,应在一个试点项目或一个组织单元实施过程改进,因为这属于试验阶段并且能够使风险降到最低。接下来,在试点项目中获得的经验可以作为案例应用于其他项目的测试过程改进。这样,当针对其他域进行改进时,可以使用这些可见的结果支持测试过程改进。
改进措施应彻底按照计划执行,并定期监控,以确保这些改进符合要求或业务目标。测试过程改进应考虑使用业界普遍认可的测试成熟度模型,如测试过程改进模型(TPINext) 作为参照。这样,可以很好分析测试过程的当前情况。
测试过程改进模型提供的成熟度基准可以帮助组织评估其测试过程的质量、识别必要的改变,并提供改进的方向,最终导向项目的成功。
样本展示:

评估结果的SWOT分析
开展评估&改进能带来什么好处?
测试过程改进能够帮助企业实现所需的测试成熟度级别和更合理、更高效的测试过程。它能够使企业优化他们的测试能力和测试过程的交付时间,并确保IT系统的整体质量。它包括了其他几个子元素,如缺陷管理、测试技术、测试工具、自动化测试、测试策略、测试环境、测试覆盖率、测试过程创新、测试远景和目标、角色和职责等。企业明确要改善的重点领域非常重要,因为不可能所有领域都处于同一成熟度级别。
测试过程评估&改进的好处列出如下,但不仅限于此:
● 对组织的强弱项做出明确的评估以及把软件开发生命周期与业界最佳实践进行比较
● 明确的路线图指出改进建议优先级
● 为后续的改进和度量建立基准
● 设置了切合实际的目标和基于这些目标的度量指标
● 提供了经实践验证的框架能够满足不同的需要
● 建立良好的测试过程,由于质量的提高以及与业务目标保持一致,因此能产生良好的ROI
● 提供了一个框架以确测试过程改进中对预期的ROI进行监控并实现
● 更有效和高效的业务运营
● 增强对测试过程和相关费用的控制
● 减少空闲时间
● 减少错误
● 降低生产维护的管理费用
● 从长远来看,减少测试的成本
● 从长远来看,减少测试过程的长度
● 提高开发和测试的生命周期以及支持过程的效率
● 提升代码的发布质量以及每个测试阶段的代码质量
测试过程评估与改进的总体目标是确保通过持续的改进来优化公司的投资回报率,并增加商业价值。
样本展示:

改善建议–测试域:测试度量
前言:
在J2EE中,注解使得开发更加便利,省去了生成XML文件的过程,在Hibernate实体声明中,可以简简单单的用几个注解就可以免去生成一个XML的文件操作。这里就主要论述一下annotation的用法和自定义注解处理器。当在创建描述符性质的类或接口时,有大量重复性的工作时候,就可以利用注解来实现。
基本语法:
Java目前包括三种标准注解和四种元注解。元注解主要负责注解其他注解的。
三种标准注解:
@Override,表示当前的方法定义覆盖了父类中的方法。必须要有相同的方法签名即(方法名,参数类型,参数顺序,参数个数)都一样。否则在编译过程中发出错误提示。
@Deprecated,对不应该再使用的方法添加注解,当使用这个方法的时候,会在编译时候显示提示信息。
@SuppressWarnings,关闭不当的编译器报警信息
四种元注解:
@Target,表示该注解可以用什么地方。
如CONSTRUCTOR,构造器声明;FIELD,域声明;METHOD,方法声明;TYPE,类,接口或enum声明
@Retention,表示需要在什么级别保存该注解信息。
如SOURCE,注解将被编译器丢弃;CLASS,注解在class文件可用,但会被VM丢弃
RUNTIME,VM将在运行期间也保留注解,可以使用反射机制读取注解信息
@Documented,将此注解包含到Javadoc中。
@Inherited,允许子类继承父类的注解。
定义注解:
自定义注解是以@interface为标志的。如同一个接口的定义,这里面定义的每个方法名,就是使用注解时候的元素名,方法的返回值就是元素的类型,可以利用default来声明默认值,不过对于非基本类型,不能设置为null为默认值,一般对于字符串使用空字符串作为其默认值。
如下所示:
package whut.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //定义一个注解 @Target(ElementType.METHOD)//定义该注解将应用于什么地方,方法或者域 @Retention(RetentionPolicy.RUNTIME)//定义该注解在哪一个级别可用 public @interface UseCase { //注解元素,可以指定默认值,在使用注解的时候,可以直接给元素赋值如id=5 public int id(); public String description() default "no description"; //利用枚举来设置参数类型 public enum ParameterType { STRING, SHORT, INT, BOOL, LONG, OBJECT }; // 默认值,在使用注解的时候,只需要为元素赋值 public ParameterType type() default ParameterType.STRING; } |
使用注解:
在类中任意的域值前,或者方法前等直接@注解名,如@UseCase(id=5),使用注解的过程中,必须对于没有设置默认值的元素进行赋值操作,对于每个元素进行按照名-值对的方式赋值。如果在注解定义中有名为value的元素,并且它是唯一需要赋值的,可以直接在括号里给出value所需要的值。
注解是不能继承的。
下面是一个基本的利用非apt实现的注解处理器模型。
这个模型可以注解实体,进行数据库的映射建表操作。是最最基本的操作。
注解定义:将四个注解名是在不同的文件中。
package whut.annotationDB; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) //定义字段的约束 public @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; } //////////////////////////// package whut.annotationDB; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE)//类,接口或enum @Retention(RetentionPolicy.RUNTIME) //定义表名的注解 public @interface DBTable { public String name() default ""; } /////////////////////////// package whut.annotationDB; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD)//类,接口或enum @Retention(RetentionPolicy.RUNTIME) public @interface SQLInteger { String name() default ""; //嵌套注解的功能,将column类型的数据库约束信息嵌入其中 Constraints constraints() default @Constraints; } /////////////////////////////// package whut.annotationDB; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD)//类,接口或enum @Retention(RetentionPolicy.RUNTIME) public @interface SQLString { int value() default 0; String name() default ""; //注解元素中引用别的注解, Constraints constraints() default @Constraints; } |
实体使用注解:这里是运用了运行时候处理注解,所以RetentionPolicy.RUNTIME
package whut.annotationDB; @DBTable(name="MEMBER") public class Member { //在使用注解过程中,如果有元素是value,并且只有value需要赋值, //则只需要在()中将值写入 @SQLString(30) private String firstName; @SQLString(50) private String lastName; @SQLInteger private Integer age; @SQLString(value=30,constraints=@Constraints(primaryKey=true)) private String handle; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getHandle() { return handle; } public void setHandle(String handle) { this.handle = handle; } } |
具体的非apt实现的注解处理器:
package whut.annotationDB; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class TableCreator { public Connection getConnection() { String user = "root"; String password = ""; String serverUrl = "jdbc:mysql://localhost:3306/carrent?user=root&password="; try { Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection(serverUrl, user, password); return con; } catch (Exception e) { e.printStackTrace(); return null; } } //实现创建表 public static void main(String[] args) { TableCreator tc = new TableCreator(); tc.executeCreateDB(Member.class); } public void executeCreateDB(Class<?> entity) { String sqlStr = explainAnnotation(entity); Connection con = getConnection(); PreparedStatement psql = null; if (con != null && !sqlStr.equals("error")) { try { psql = con.prepareStatement(sqlStr); psql.execute(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (psql != null) psql.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (con != null) psql.close(); } catch (SQLException e) { e.printStackTrace(); } } } else System.out.println("failure to..."); } // 真正的处理器,Class<?>必须用这个表明 public String explainAnnotation(Class<?> entity) { // 获取指定类型的注解 DBTable dbtable = entity.getAnnotation(DBTable.class); if (dbtable == null) { System.out.println("No DBTable annotation in class" + entity.getName()); return "error"; } else { String tableName = dbtable.name();// 获取注解name值,即表名称 // 当没有设置name值,直接利用类的名作为表名 if (tableName.length() < 1) tableName = entity.getName().toUpperCase();// 转换大写 // 准备处理字段注解 List<String> columnsDefs = new ArrayList<String>(); // 获取该类的所有字段 for (Field field : entity.getDeclaredFields()) { String columnName = null; // 获取该字段所有的注解 Annotation[] anns = field.getDeclaredAnnotations(); // Annotation[] anns=field.getAnnotations(); // 当有注解的时候 if (anns.length >= 1) { // 判断注解的类型 if (anns[0] instanceof SQLInteger) { SQLInteger sInt = (SQLInteger) anns[0]; // 当没有name时候,将字段大写为列名 if (sInt.name().length() < 1) columnName = field.getName().toUpperCase(); else columnName = sInt.name(); columnsDefs.add(columnName + " INT" + getConstraints(sInt.constraints())); } if (anns[0] instanceof SQLString) { SQLString sString = (SQLString) anns[0]; // 当没有name时候,将字段大写为列名 if (sString.name().length() < 1) columnName = field.getName().toUpperCase(); else columnName = sString.name(); columnsDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints())); } } } StringBuilder createDB = new StringBuilder("CREATE TABLE " + tableName + "("); for (String cols : columnsDefs) createDB.append(" " + cols + ","); // 移除最后一个,号 String tableSQL = createDB.substring(0, createDB.length() - 1) + ");"; // 输出创建表的过程 System.out.println("Table Creation SQL is:\n" + tableSQL); return tableSQL; } } // 返回指定的约束 public String getConstraints(Constraints con) { String constras = ""; if (!con.allowNull()) constras += " NOT NULL"; if (con.primaryKey()) constras += " PRIMARY KEY"; if (con.unique()) constras += " UNIQUE"; return constras; } } |
数据库连接的建立及关闭是一种极耗系统资源的操作,尤其是在多层结构的应用环境中,这种资源的耗费对系统性能影响尤为明显。在工作时做系统优化对这方面的很有体会,相同功能的查询语句,由于打开关闭数据库连接的次数不同导致两个查询语句耗费的时间差别很大。一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完后立即关闭连接。频繁地打开、关闭连接将会造成系统性能低下。虽然写高性能的sql语句能够减少访问数据库的次数,但是也不能完全规避平凡操作数据库的的行为,因为有时候我们访问量大,就会伴有多线程和高并发,这时候我们就该考虑还有什么办法能提高系统的性能了。办法总比问题多,数据库连接池的使用帮我们大大的降低了平凡的开关数据库。
数据库连接池的解决方案是:当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从池中取出已有的连接使用,使用完后,虽然使用了close()关闭连接,但是没有真正关闭数据库连接,而是直接将连接归还给了连接池。通过使用连接池,将大大提高程序运行效率。
1、数据库连接池是Connection对象的工厂。数据库连接池的常用参数有如下:
● 数据库的初始连接数
● 连接池的最大连接数
● 连接池的最小连接数
● 连接池的每次增加的容量
... ...
2、JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由商用服务器(如webLogic、WebSphere)等提供实现,也有一些开源组织提供实现(如DBCP和 C3P0等)。商用的我就不多介绍了,一般都是根据提示配置一下就可以使用了。下面简单的说一下上面这两个开源的常用配置属性,真用到了还可以参考文档进行详细的配置。
3、DBCP(DataBaseconnection pool),数据库连接池。是apache上的一个java连接池,也是tomcat使用的连接池组件。单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。下面是一些常用的设置属性
//创建数据源对象 BasicDataSource ds = new BasicDataSource(); //设置连接池所需的驱动(以MySql为例) ds.SetDriverClassName("com.mysql.jdbc.Driver"); //设置连接数据库的url ds.setUrl("jdbc:mysql://localhost:3306/javaee"); //设置连接数据库的用户名 ds.setUsername("root"); //连接数据库的密码 ds.setPassword("root"); //设置连接池的初始连接数 ds.setInitia1Size(5); //设置连接池最多可有有多少个活动连接数 ds.setMaxActive(10); //设置连接池中最少有2个空闲的连接 ds.setMinIdle(2); //通过数据源获取连接 Connection conn = ds.getConnection(); //释放数据库连接 Conn.close(); |
数据源和数据库连接不同,数据源无须创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。建议把上面程序中的ds设置成static成员变最,并且在应用开始时立即初始化数据源对象,程序中所有需要获取数据库连接的地方直接访问该ds对象,并获取数据库连接即可,当数据库访问结束后,程序还是像以前一样关闭数据库连接即可。
4、C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0不仅可以自动清理不在使用的Connection,还可以自动清理Statement和ResultSet。目前使用它的开源框架有Hibernate,Spring等。
//创建连接池对象 ComboPooledDataSource ds = new ComboPooledDataSource(); //设置连接池所需的驱动(以MySql为例) ds.SetDriverClass("com.mysql.jdbc.Driver"); //设置连接数据库的url ds.setJdbcUrl("jdbc:mysql://localhost:3306/javaee"); //设置连接数据库的用户名 ds.setUser("root"); //连接数据库的密码 ds.setPassword("root"); //设置连接池的最大连接数 ds.setMaxPoolSize(20); //设置连接池中最少连接数 ds.setMinPoolSize(2); //设置连接池的初始连接数 ds.setInitia1PoolSize(5); //设置连接池的缓存Statement的最大数 ds.setMaxStatements(100); //获取连接 Connection conn = ds.getConnection(); //释放数据库连接 Conn.close(); |
看到了数据库连接池的使用,我们是不是很快就会想到多线程编程里是不是也有线程池帮我们解决一些性能问题呢?答案肯定的,想到了就去尝试吧......