流程说明
1、测试人员填写bug并提交给开发组长,Bug的状态为New;
2、开发组长次日工作前对bug确认是否有效。有效的bug,状态变化为open,并分配给开发人员;bug无效或者延期修改的,将bug状态变化为Rejected,同时也在comment中注明原因。
3、开发人员上班的第一件事情是查看自己有几个bug需要修改。
4、开发人员修改bug,修改完成并进行单元测试后,将bug的状态变为fixed,在comment中说明修改方法;
5、测试人员每天查看自己提交的bug的状态变化,应该成为每个测试人员的例行行为;
6、当bug的状态变为fixed时,测试人员打开该bug,开始对该bug进行回归测试;
7、如果该bug回归测试通过,则状态变为closed。否则bug的状态变为reopen(必须说明reopen、closed状态变化原因或者操作过程);
8、如果回归测试通过,可是修改的同时又引入新的bug,则重新提交bug,状态为new。如果需要的时候注明相关联的bug号;
9、只有当所有的bug状态为closed,才可发布版本。
注:每当bug状态改变后,必须给出相应的注释和说明,以便查看bug生命周期的变化情况。
与其他语言的模型相比,finally 关键字是对 Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。 如果没有 finally,您的代码就会很费解。例如,下面的代码说明,在不使用 finally 的情况下您必须如何编写代码来释放非内存资源:
- import java.net.*;
- import java.io.*;
- class WithoutFinally
- {
- public void foo() throws IOException
- {
- //在任一个空闲的端口上创建一个套接字
- ServerSocket ss = new ServerSocket(0);
- try
- {
- Socket socket = ss.accept();
- //此处的其他代码...
- }
- catch (IOException e)
- {
- ss.close(); //1
- throw e;
- }
- //...
- ss.close(); //2
- }
- }
|
这段代码创建了一个套接字,并调用 accept 方法。在退出该方法之前,您必须关闭此套接字,以避免资源漏洞。为了完成这一任务,我们在 //2 处调用 close,它是该方法的最后一条语句。但是,如果 try 块中发生一个异常会怎么样呢?在这种情况下,//2 处的 close 调用永远不会发生。因此,您必须捕获这个异常,并在重新发出这个异常之前在 //1 处插入对 close 的另一个调用。这样就可以确保在退出该方法之前关闭套接字。
这样编写代码既麻烦又易于出错,但在没有 finally 的情况下这是必不可少的。不幸的是,在没有 finally 机制的语言中,程序员就可能忘记以这种方式组织他们的代码,从而导致资源漏洞。Java 中的 finally 子句解决了这个问题。有了 finally,前面的代码就可以重写为以下的形式:
- import java.net.*;
- import java.io.*;
- class WithFinally
- {
- public void foo2() throws IOException
- {
- //在任一个空闲的端口上创建一个套接字
- ServerSocket ss = new ServerSocket(0);
- try
- {
- Socket socket = ss.accept();
- //此处的其他代码...
- }
- finally
- {
- ss.close();
- }
- }
- }
|
finally 块确保 close 方法总被执行,而不管 try 块内是否发出异常。因此,可以确保在退出该方法之前总会调用 close 方法。这样您就可以确信套接字被关闭并且您没有泄漏资源。在此方法中不需要再有一个 catch 块。在第一个示例中提供 catch 块只是为了关闭套接字,现在这是通过 finally 关闭的。如果您确实提供了一个 catch 块,则 finally 块中的代码在 catch 块完成以后执行。
finally 块必须与 try 或 try/catch 块配合使用。此外,不可能退出 try 块而不执行其 finally 块。如果 finally 块存在,则它总会执行。(无论从那点看,这个陈述都是正确的。有一种方法可以退出 try 块而不执行 finally 块。如果代码在 try 内部执行一条 System.exit(0); 语句,则应用程序终止而不会执行 finally 执行。另一方面,如果您在 try 块执行期间拨掉电源,finally 也不会执行。)
七、详细设计
详细设计还得从数据库开始。作为专业菜鸟,我们要把所有的SQL语句都放在存储过程当中,不要放在程序里。这样做的好处是:容易修改、维护,执行速度快、减少数据传输量。存储过程可以简单的理解为在SQL服务器上创建小函数,它们有名字、参数,通过调用这些小函数,我们可以完成对表的增、删、查、改操作,相当于把SQL语句放在了服务器上,并且是经过编译的,执行速度快。在程序中,我们不必再写复杂的SQL语句,直接写存储过程名称就可以了。
具体如何使用存储过程,可以参考这篇博文:http://www.51testing.com/html/60/n-814760.html
一定要仔细研究上边那篇文章,因为这是数据库使用的经典例子,把他搞懂了使用数据就没什么问题了,我就偷个懒,不在重复写啦。
如果遇到一些问题,或许这篇文章会帮你:http://www.51testing.com/html/59/n-814759.html
另外,可以看出,本教程的例子,班级表依赖年级表,学生表依赖班级表,所以在删除记录时,必须级联删除,级联删除可以在程序中完成,但我还是比较喜欢放在SQL触发器中。触发器的使用方法和存储过程大同小异,在这就不赘述了,可以google。
详细设计还是要用到UML图,这回用的一般是时序图和流程图,其他的虽然重要,但是比较少用,具体的还是google。
很遗憾的告诉大家,教程到此就结束了,细节上远远没有结束,存储过程具体代码、各层的代码都没有写,UML的图还有很多没画,但那些都是细节知识,本教程的目的是宏观指导,本小菜也需要继续学习,时间非常有限,所以只能写这么多了。
剩下的基本上都是写代码,我写出来也没啥意思,开发一个项目,基本的流程都在这呢,我主要不是教大家写代码,而不是告诉大家一个项目的流程,体会一个稍微大点的程序是怎么设计出来的,分享一下我自己的经验。跟着这个教程走,就是再菜,也是专业菜鸟!
教程中涉及大量知识点,都需要大家耐心的去查阅资料,不怕不会,就怕不知道,刚开始会用就可以了,随着学习的深入,再去搞懂细节原理。我学这些东西也不是一天两天就学成的,是大约一年半的积累,希望大家能静下心来,踏实学习。
最后,恭祝大家都能成为IT界的精英!
相关链接:
菜鸟也能飞:SQL数据库实战专业教程(一)
菜鸟也能飞:SQL数据库实战专业教程(二)SQLHelper包:
DAL包:
BLL包:
UI包:
六、概要设计
数据库分析完了,基础已经搞定,接下来就是对程序的初步设计。如何设计呢?如果是小程序,用脑子想想,也就算设计完了,但是如果是稍微复杂点的系统,恐怕就不行了。概要设计还是要借助于UML图,现在你知道它有多重要了吧?我们先来设计程序的大致结构,可以用UML的包图。作为专业水准的菜鸟,我们要用三层架构来设计程序。所谓三层架构,就是把程序分为基本的三层,分别为:UI层(用户界面层)、BLL层(业务逻辑层)、DAL层(数据访问层)。把程序分成三层,好处不言而喻,从此你就再也见不到所有东西都在一个窗体里混乱的情形,如果什么地方需要修改,再也不用去改动整个工程。每一层都有各自的功能,从UI层到DAL层,它们是向下依赖的。其中,UI层只负责显示界面,不应该有逻辑(有效性验证的逻辑还是可以有的),所有的功能都是通过调用BLL层完成;BLL层负责程序的所有逻辑组织,它通过调用DAL层完成复杂的操作,然后提供一个简洁的接口让UI层调用,相当于一个大外观层,BLL层的类,可以按照窗体写,也就是说每一个窗体对应一个BLL层的类,类的各种方法完成窗体的所有功能;DAL层负责访问数据库,数据库中每一个表,在DAL层中都有一个与之对应的操作类,通过该操作类,可以实现对对应表的一切操作。前边提到的实体类,就是为三层架构服务的,三层之间一般都是通过实体类传递数据,这样简洁、方便,实体类就相当于一个容器。注意,还有一个层,也可以不单独作为一个层的DBHelper,这个部分负责最低级的与数据库交互代码,比如连接数据库、插入数据、查询数据等等,把这些最基本的代码提炼到一个单独的层中有利于代码的复用,使程序更加精炼。欲知其他知识,请轻点google,我说到此为止。献上一张三层架构的示意图:
再来一个数据库、DAL操作类、实体类的关系,这个有点乱,刚开始不好理解,多想想就知道啦:
有了上边的分析,我们就可以用Rational Rose画程序包图了,提一个小技巧,Rose的包理论上应该在包图里画,但是那样没法画类,所以还是建议在类图里画包,用包把类图分成几个大部分,然后在每个部分里画特定的类,这样双击包直接就可以看到该包中的类了。根据三层架构,我们可以画出下边的包图:
整体架构就是这样了,接下来就搞定每个包里都有什么类。
1、原始单据与实体之间的关系
可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体。这里的实体可以理解为基本表。明确这种对应关系后,对我们设计录入界面大有好处。
〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。
2、主键与外键
一般而言,一个实体不能既无主键又无外键。在E—R图中,处于叶子部位的实体,可以定义主键,也可以不定义主键(因为它无子孙),但必须要有外键(因为它有父亲)。
主键与外键的设计,在全局数据库的设计中,占有重要地位。当全局数据库的设计完成以后,有个美国数据库设计专家说:“键,到处都是键,除了键之外,什么也没有”,这就是他的数据库设计经验之谈,也反映了他对信息系统核心(数据模型)的高度抽象思想。因为:主键是实体的高度抽象,主键与外键的配对,表示实体之间的连接。
3、基本表的性质
基本表与中间表、临时表不同,因为它具有如下四个特性:
(1)原子性。基本表中的字段是不可再分解的。
(2)原始性。基本表中的记录是原始数据(基础数据)的记录。
(3)演绎性。由基本表与代码表中的数据,可以派生出所有的输出数据。
(4)稳定性。基本表的结构是相对稳定的,表中的记录是要长期保存的。
理解基本表的性质后,在设计数据库时,就能将基本表与中间表、临时表区分开来。
4、范式标准
基本表及其字段之间的关系,应尽量满足第三范式。但是,满足第三范式的数据库设计,往往不是最好的设计。
为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间的目的。
〖例2〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加“金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。
在Rose2002中,规定列有两种类型:数据列和计算列。“金额”这样的列被称为“计算列”,而“单价”和“数量”这样的列被称为“数据列”。
表1商品表的表结构
商品名称商品型号单价数量金额
电视机29吋2,50040100,000
5、通俗地理解三个范式
通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就必须通俗地理解
三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解):
第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;
第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。
没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。
6、要善于识别与正确处理多对多的关系
若两个实体之间存在多对多的关系,则应消除这种关系。消除的办法是,在两者之间增加第三个实体。这样,原来一个多对多的关系,现在变为两个一对多的关系。要将原来两个实体的属性合理地分配到三个实体中去。这里的第三个实体,实质上是一个较复杂的关系,它对应一张基本表。一般来讲,数据库设计工具不能识别多对多的关系,但能处理多对多的关系。
〖例3〗:在“图书馆信息系统”中,“图书”是一个实体,“读者”也是一个实体。这两个实体之间的关系,是一个典型的多对多关系:一本图书在不同时间可以被多个读者借阅,一个读者又可以借多本图书。为此,要在二者之间增加第三个实体,该实体取名为“借还书”,它的属性为:借还时间、借还标志(0表示借书,1表示还书),另外,它还应该有两个外键(“图书”的主键,“读者”的主键),使它能与“图书”和“读者”连接。
7、主键PK的取值方法
PK是供程序员使用的表间连接工具,可以是一无物理意义的数字串,由程序自动加1来实现。也可以是有物理意义的字段名或字段名的组合。不过前者比后者好。当PK是字段名的组合时,建议字段的个数不要太多,多了不但索引占用空间大,而且速度也慢。
8、正确认识数据冗余
主键与外键在多表中的重复出现,不属于数据冗余,这个概念必须清楚,事实上有许多人还不清楚。非键字段的重复出现,才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的重复出现,而是字段的派生出现。
〖例4〗:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提高处理速度。只有低级冗余才会增加数据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。因此,我们提倡高级冗余(派生性冗余),反对低级冗余(重复性冗余)。
9、E--R图没有标准答案
信息系统的E--R图没有标准答案,因为它的设计与画法不是惟一的,只要它覆盖了系统需求的业务范围和功能内容,就是可行的。反之要修改E--R图。尽管它没有惟一的标准答案,并不意味着可以随意设计。好的E—R图的标准是:结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。
10、视图技术在数据库设计中很有用
与基本表、代码表、中间表不同,视图是一种虚表,它依赖数据源的实表而存在。视图是供程序员使用数据库的一个窗口,是基表数据综合的一种形式,是数据处理的一种方法,是用户数据保密的一种手段。为了进行复杂处理、提高运算速度和节省存储空间,视图的定义深度一般不得超过三层。若三层视图仍不够用,则应在视图上定义临时表,在临时表上再定义视图。这样反复交迭定义,视图的深度就不受限制了。
对于某些与国家政治、经济、技术、军事和安全利益有关的信息系统,视图的作用更加重要。这些系统的基本表完成物理设计之后,立即在基本表上建立第一层视图,这层视图的个数和结构,与基本表的个数和结构是完全相同。并且规定,所有的程序员,一律只准在视图上操作。只有数据库管理员,带着多个人员共同掌握的“安全钥匙”,才能直接在基本表上操作。请读者想想:这是为什么?
11、中间表、报表和临时表
中间表是存放统计数据的表,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与外键(数据仓库除外)。临时表是程序员个人设计的,存放临时记录,为个人所用。基表和中间表由DBA维护,临时表由程序员自己用程序自动维护。
12、完整性约束表现在三个方面
域的完整性:用Check来实现约束,在数据库设计工具中,对字段的取值范围进行定义时,有一个Check按钮,通过它定义字段的值城。
参照完整性:用PK、FK、表级触发器来实现。
用户定义完整性:它是一些业务规则,用存储过程和触发器来实现。
13、防止数据库设计打补丁的方法是“三少原则”
(1)一个数据库中表的个数越少越好。只有表的个数少了,才能说明系统的E--R图少而精,去掉了重复的多余的实体,形成了对客观世界的高度抽象,进行了系统的数据集成,防止了打补丁式的设计;
(2)一个表中组合主键的字段个数越少越好。因为主键的作用,一是建主键索引,二是做为子表的外键,所以组合主键的字段个数少了,不仅节省了运行时间,而且节省了索引存储空间;
(3)一个表中的字段个数越少越好。只有字段的个数少了,才能说明在系统中不存在数据重复,且很少有数据冗余,更重要的是督促读者学会“列变行”,这样就防止了将子表中的字段拉入到主表中去,在主表中留下许多空余的字段。所谓“列变行”,就是将主表中的一部分内容拉出去,另外单独建一个子表。这个方法很简单,有的人就是不习惯、不采纳、不执行。
数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。“三少”是一个整体概念,综合观点,不能孤立某一个原则。该原则是相对的,不是绝对的。“三多”原则肯定是错误的。试想:若覆盖系统同样的功能,一百个实体(共一千个属性)的E--R图,肯定比二百个实体(共二千个属性)的E--R图,要好得多。
提倡“三少”原则,是叫读者学会利用数据库设计技术进行系统的数据集成。数据集成的步骤是将文件系统集成为应用数据库,将应用数据库集成为主题数据库,将主题数据库集成为全局综合数据库。集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E—R图中实体的个数、主键的个数、属性的个数就会越少。
提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院”,最后造成数据库中的基本表、代码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。
“三多”原则任何人都可以做到,该原则是“打补丁方法”设计数据库的歪理学说。“三少”原则是少而精的原则,它要求有较高的数据库设计技巧与艺术,不是任何人都能做到的,因为该原则是杜绝用“打补丁方法”设计数据库的理论依据。
14、提高数据库运行效率的办法
在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是:
(1)在数据库物理设计时,降低范式,增加冗余,少用触发器,多用存储过程。
(2)当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。
(3)发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是,以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过八十个,则垂直分割该表,将原来的一个表分解为两个表。
(4)对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。
(5)在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。
总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化,这三个层次上同时下功夫。
上述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的。对于这些经验的运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握。并逐步做到:在应用中发展,在发展中应用。
自动化测试架构之说
测试人员经常想象——在无人值守的情况下,每天晚上测试工具自动运行成千上万的测试用例,第二天早晨去上班,一打开电脑就能看到所有的测试任务已全部执行完毕,测试报告也整整齐齐地出现在我们面前。如果能亲身经历这种场景,一定会感到无比兴奋和轻松!这种情景不是梦想,也并不遥远,完全是可以实现的,只要借助一套灵活、可扩展的自动化测试框架即可帮助我们实现梦想。
为何要建立自动化测试架构
在过去几十年中,自动化测试已经有了良好的发展。最初的测试工具只提供了简单的捕捉/回放功能:记录键盘和鼠标的操作,并捕捉屏幕,然后通过播放所记录的操作进行验证。这样的脚本很难维护,从而要求开发功能和灵活性更强的测试工具,并能将这些工具很好地整合起来,使整个自动化测试过程的各个部分或各个阶段能很好地衔接起来。这就需要构造一个完整的自动化体系,形成自动化测试的流水线,使整个测试过程一气呵成。这其中,不仅要包括自动化测试的执行,还要包括自动化测试脚本的开发、软件包自动部署以及测试报告自动生成等,才能将自动化开发、执行和日常工作融合在一起。这一切都需依赖于自动化测试架构。
针对上述讨论,我们深知自动化测试所面临的挑战。面对挑战,必须采取以下这些相应的对策,通过构建适应性很强的自动化测试框架来解决一系列问题。
1)需求频繁的变化要求自动化测试具有一个灵活的适应机制。我们知道,建造商品住房时,如果只浇灌混凝土框架,没有砌墙,那么住户就有更大的灵活性来设计自己的家,可以满足住户更多的个人需求。在某些商场、写字楼的建筑上,这种考虑表现得更为充分,保留了很大的灵活空间供商家租用和装修。
2)单元测试、集成测试和系统测试等的自动化实施能共享某些平台和机制,让这些测试有机地结合起来。例如,房屋的各个功能模块,包括卧室、会客厅、厨房、卫生间、窗户、屋顶等都要有框架支撑,才能形成实用的、功能完整的住宅。
3)大规模软件团队的协作和硬件资源的使用效率都要求一个良好的基础设施来支撑自动化测试。例如,房屋的各个单元之间需要通过布置电线、水管、暖气管、有线电视等网络,才能有机地结合起来,更好地支撑各个功能之间的协调和使用,更好地为住宅的主人服务。
从上面这些举例可以得知,自动化测试也不例外,在进行具体的单元自动化测试、功能自动化测试和系统自动化测试之前,先要建立一个清晰的框架,才能包容自动化测试的各个功能单元,使将来各项自动化测试任务有机地结合起来,顺利地开展工作。
解决什么问题
作为自动化测试框架,最根本的是要构造一个良好的工作空间,能够容纳各种类型测试工具的执行,以使这些工具能够相互兼容,共享测试数据。如果能够像Windows 操作系统那样支持即插即用,任何测试工具都可以动态、方便地加入系统或从系统中移除,则再好不过。
其次,自动化测试框架需要能够监控测试执行的过程,包括监控测试对象资源(如CPU、内存等)的使用,及时收集来自不同测试工具的测试结果,并将这些结果进行归类和分析,生成相应的测试报告,通过邮件和网站等发布出去。
再者,为了让测试能够在某个特定时刻(例如晚上)自动执行,自动化测试框架应具有事先安排(schedule)任务能力,并能够支持维护测试环境和管理测试资源,包括管理硬件资源列表、支持测试状态查询和自动分发测试任务到相应的测试机器上,并在规定的时间内完成测试任务。
最后,自动化测试框架还应能支持自动化测试的前期任务,支持测试脚本的录制、编辑和调试,支持测试脚本的快速开发和良好的维护性,而且能够支持测试用例、测试套件(test suite)和其他测试活动的管理。
要构建良好的自动化测试框架,还需要提供一些基础设施来支持自动化测试,例如邮件服务、跨平台的通信服务、分布式开发和运行环境等,如图2-7 所示,一个良好的自动化测试框架应具有下列能力。
1)提供非常有效的测试工作流程模型,如对任务安排、执行、通知结果和生成报告等完整的过程支持。
2)支持多种脚本语言的录制、编辑、调试和回放等集成开发环境。
3)完成各类测试任务的执行。
4)有良好的扩充能力,如和第三方插件、工具的集成。
5)具有数据驱动、关键字驱动等脚本模式的支持。
6)具有分布式处理、远程调用等不同的运行方式。
7)能获取测试覆盖率。
图2-7 自动化测试框架要解决的问题
如果进一步抽象,自动化测试框架就是用来解决自动化测试中的公共问题的,包括公用的对象、公用的方法、公用的环境或数据等自动化测试框架的要素。
1)公用的对象。不同的测试用例会有一些相同的对象(如窗口、按钮、菜单等)被重复使用,而这些公用的对象可以被抽取出来,在编写脚本时随时调用。如果需求发生变化,只需要修改这些公用对象的属性即可,而不需要修改太多的测试脚本。而要做到这一点,就要求我们构建对象库,并建立实体对象和逻辑对象之间的映射。
2)公用的方法。公用的方法比较多,相当于脚本的基础函数,可以构成基础函数库,供上层脚本调用。
3)公用的环境或数据。许多测试用例会在相同的测试环境上运行或使用相同的测试数据,可将不同的测试环境或数据封装起来,和测试用例进行灵活的组合,以增强脚本执行的灵活性,并覆盖更广的测试范围,降低测试风险。
自动化测试框架应支持脚本录制、脚本开发、测试用例和测试套件的创建和执行、远程控制、分布式通信等功能,才能基本满足测试自动化的需要。自动化测试框架还需要支持单元测试并与开发环境集成,如将集成开发环境Eclipse、软件配置管理工具CVS/SubVersion 和软件包构建工具Ant/Maven等集成到这个框架中,以支持每日构建和自动验证测试。
如果自动化测试框架能管理测试项目、安排任务,将产品用户需求和测试需求很好地结合起来,那么测试目标更明确,测试的效率会得到进一步提高。测试结果的分析也是很重要的,一般要求在自动化测试框架中得到解决。最重要的是易用,将各个工具集成起来,并能使这些工具更好地发挥作用。例如,openqa.org 社区提供了一个工具Bromine,它集成了Selenium Core/RC,非常容易跟踪和管理测试项目、需求、测试计划、测试用例和缺陷,可以监控缺陷的提交,将缺陷分派给相应的开发人员来浏览和分析测试结果。
一个理想的自动化测试框架能解决上述问题,提供一个分布式的通信平台、友好的人机交互界面和开放式架构,将自动化测试中所需要的各个关键部分有机地集成起来,形成一个为自动化测试服务的、完整的、层次清楚的开发平台和运行环境,如图2-8 所示,其中各主要部分的功能如下。
图2-8 自动化测试框架示意图
1)综合管理平台:可以将自动化测试中所有的工作内容管理起来,相当于一个统一的入口(Portal),可以浏览每部分的内容。
2)基于业务驱动的脚本集成开发环境:可便于构造关键字驱动的脚本,为此要建立软件系统的对象库,并将这些对象映射为脚本中的逻辑对象,以减少软件需求变化对脚本的影响。这个集成开发环境还包括脚本录制、编辑等功能,并能和CVS、Ant 等工具集成。其中库函数可以看做是关键字列表和关键字实现,而对象映射可以看做是由对象库和映射关系构成的。
3)安排(Schedule)测试任务:使任务可以定时启动,自带执行测试任务。
4)监控测试资源:在测试过程中,能够及时发现问题,发出警告,并保留(记录)相关数据。
5)控制中心(控制器):驱动测试工具,可以调用测试任务,并将测试任务、测试脚本等分发给远程机器。
6)远程机器执行测试任务:通过代理实现,而代理由控制中心来控制。
相关链接:
工具介绍
Firebug: 这个不介绍了,居家旅行杀人越货必备的Firefox插件
YSlow: 当Firefox浏览网页时,可以分析网站的页面(基于Yahoo 14条评分原则),并告诉你为了提高网站性能,如何基于某些规则而进行优化
ShowSlow:收集YSlow的测试结果并显示出来
思路整理
使用Selenium编写测试用例依次访问需要测试的站点,设置YSlow每打开一个页面自动运行测试,并将测试报告发送到指定的ShowSlow服务器,建议可以和我前几天说的自动化框架搭配使用,何乐而不为:)
环境配置
搭建本地ShowSlow平台
默认情况下YSlow的结果会发送到ShowSlow(印象中),但这显然不符合天朝国情,同时也及其不和谐,还好ShowSlow开源网站提供源码可以在本地搭建一个平台来收集YSlow的信息。主要采用Apache+PHP+Mysql这个框架,但是很不幸的告诉各位我尝试过独自手工搭建上述环境,弄坏了两台虚拟机(Win 2003)都未遂,主要在于没有相关经验,在此推荐使用 AppServ傻瓜化一体式安装吧(请尽情鄙视我,谢谢)
1.先用SVN将源码下载到本地,并放置于Apache的WWW文件夹下(请猛击我)
2.修改ShowSlow文件夹下的config.sample.php重命名为config.php,里面$db,$user,$pass可以根据实际情况修改
3.创建第2步中你填写的数据库,MySQL我也不太会,高手无视我
//创建一个数据库,名字和第二步你填写的保持一致
create database ‘DBName‘;
//切换到新建的数据库
use ‘DBName’;
// 将ShowSlow文件夹的tables.sql(数据库表)导入到新建的数据库中,注意无分号
source c:\tables.sql
//查看下是否导入成功了,貌似有个表名叫ShowSlow2,汗
show tables;
配置YSlow
1.打开Firefox输入:about:config(我保证会很小心的)
2.filter中输入:yslow
3.修改以下三条数据
extensions.yslow.beaconUrl = http://localhost/showslow/beacon/yslow/
如果测试和服务器不在同一机器上,请将localhost改成实际地址
extensions.yslow.beaconInfo = grade
extensions.yslow.optinBeacon = true
4.重启Firefox,have fun
还等什么?开始你的测试之旅吧,查看测试报告的URL是:http://localhost/showslow/
PS:Google的Page Speed和YSlow差不多,也支持发送报告至ShowSlow,有兴趣的同学可以试试
在几年的测试工作中,大部分工作内容都是在编写测试脚本(或测试程序)。而测试脚本设计写主要包含应用测试脚本和底层测试脚本的设计。甭管是哪种,设计他们的目的是实现测试用例的输入\输出平台,设计方向都是自动化测试方向。使测试实施中尽量提高自动化测试程度,从而使测试人员把更多的心思或经历投入到测试设计中。测试脚本设计也是测试设计之一。
大多数人可能认为,测试脚本只要实现测试用例数据的输入就好了,只要能输入测试数据和得到预期的测试结果数据就可以了。个人认为,这种想法是初级的,肤浅的。测试脚本的设计不仅要求能实现测试数据的输入和输出,同时也要考虑测试脚本结构的合理性,及可维护性。同时更要考虑到测试脚本的正确性和可靠性。想想,如果测试程序都不可靠了,那他产生的输出还可靠吗?良好的脚本组织结构固然重要,所以各公司可能有不同的脚本框架来保证,测试脚本结构的合理性和可维护性。我所经历的脚本设计,从开始的流水式脚本设计到结构化脚本设计,再由结构化脚本设计到框架脚本设计,再到最后框架脚本设计和测试平台配合使用的设计,逐步精化设计,逐步简化设计,逐步自动化执行。可以说在这方面的技术已经相当的成熟了。但是唯一不足的就是同一脚本,在不同平台或回归测试时,多少都会有个别用例测试不通过,而不通过的原因经过分析会发现是脚本存在的问题。
所以,脚本设计时的调试仅仅是保证测试脚本正确的一种有效的手段。但脚本设计时,个人认为不仅要从开发的角度,同时还要从测试专业角度来考虑设计,如数组边界处理,死循环处理,空指针,类型转换等。
总之,良好的编程习惯和基础能够帮助测试设计人员更好的开发测试脚本,但利用专业的测试知识去开发测试脚本,能够更好的避免由于测试脚本的问题而引发的测试缺陷。从而增加测试结果可靠性和缩短测试周期的一种有效的,高效的方法和手段。
由于受到极限编程的影响,在最近的几年时间里单元测试逐渐成为我软件开发过程中一个不可或缺的重要组成部分。极限编程要求我们对我们所完成的每一项功能都要进行单元测试并且要很好的管理这些测试,我们不应该在所有的单元测试通过之前去集成任何新的功能。这种做法的好处就是可以让开发人员对自己所写的代码充满信心(而不是盲目的毫无根据的自负)。
最开始我认为既然已经有了单元测试了,就没有必要再去花时间在功能测试上了,可我现在知道这是一个错误的想法:单元测试和功能测试是有很大的不同的。我花了很长的时间才了解到单元测试和功能测试的差异所在,我也知道了怎样更好的运用单元测试和功能测试来完善我们的软件开发流程。
这篇文章探究了单元测试和功能测试的不同点以及我们可以怎样运用这两种测试来支持我们的软件开发。
测试和软件开发过程
作为一个开发人员来讲,测试是相当重要的,我们必须要坚持在整个软件开发流程中测试我们的代码,而不仅仅把测试作为软件开发的一个特殊阶段的产物:测试绝对不应该成为你在软件提交前一天才开始的一个例行公事。你怎么才能知道我们的软件已经可以发布了?你怎么知道我修正了这个小bug的时候没有引发一个更严重的系统bug?你怎么知道当前的系统是否可以扩展一些现在没有想到功能呢?测试!单元测试和功能测试必须成为我们在软件开发流程中的一个有机组成部分。
单元测试应该成为你写代码的一个核心部分,尤其是在项目时间比较紧张但是我们仍然要保证质量的时候。单元测试十分重要,你甚至应该在你的代码写出来之前就应该完成单元测试。
单元测试:
-》有助于尽可能地重现最有效的设计
-》有助于提供一个最佳的文件组织结构
-》有助于确定一个类是否完成
-》让开发人员对自己的代码充满信心
-》是快速重构的基础
单元测试有助于形成系统化的并可以不断改进的设计文档,这些文档在软件开发的过程中有着极其重要的意义。大多时候将用例文档化形成一个类要比仅仅罗列一大堆编码的实际用例好,看看单元测试:它提供一系列有规律的输入或数据,用一系列的实际用例来告诉我们所写的类做了些什么。这样的话这个设计文档就总是最新的,因为我们必须通过单元测试。
你应该在写代码之前写单元测试,这样做的好处就是为自己提供了一个可以测试的设计方案,这就可以帮助你想的更加完善,这样会使设计变得简单。你不必担心将来会怎样,也不必花时间去实现一些不必要的功能。首先写单元测试还有助于帮你了解代码在什么时候完成:当所有的测试都通过之后,我们的任务也就完成了。
最后,单元测试让你对自己代码有高度的自信,这有助于我们做出更加好的产品。当你修改了自己的代码之后,我们来运行我们的测试,如果有问题的话我们可以迅速找出来我们的修改产生了在什么地方哪些破坏。
功能测试甚至比单元测试更加重要,因为它是用来检测我们的系统是否达到可以发布的要求。功能测试是用来确定我们的系统是否是一个可用的系统。
功能测试:
-》确定是否实现用户需求的一个有效方法
-》让用户和开发人员了解到我们的系统已经实现了这些用户需求
传统的开发过程是从实际使用中确定是否实现用户需求的,通常人们需要花费大力气才可以搞清楚这些实际用例并设法概括它们,当他们完成了这些工作之后他们手中无非多了一张纸而已,而功能测试就像是自己确定实际用例一样。极限编程阐述了这些观念,极限编程需要提前定义这些功能(这一过程需要项目组和用户共同完成),而功能测试就是它的产物,如果没有功能测试的话,我们不可能完成的很漂亮。
功能测试可以检查出单元测试遗留下的一些软件缺陷,让开发人员对自己的代码更加有信心,因为单元测试仍然会遗留下很多bug,它可能会覆盖到代码的各个部分但是却不能覆盖到系统的各个部分。功能测试可以揭露一些单元测试没有涉及的问题。当然一个自动化的可持续运行的功能测试不可能找出系统中的所有问题,但它可以找出更多的单元测试找不到的bug。
本文中考虑的软件测试过程专指第三方的软件测试过程,即在测试的过程中,不涉及开发人员的修复过程。
度量和分析的目的是开发和维持一个用于支持项目信息需要的度量能力。通过对项目的度量,一方面可以逐渐丰富和完善公司的度量财富库,从而为项目经理进行项目工作量、进度等的预估时提供可靠的参考依据;另一方面,通过度量分析,项目经理可以有效的对项目情况进行监控,当度量分析报告中提供的结果超过了一定的阈值时,项目经理就应该采取相应的措施,也就是说度量分析有利于项目经理做出正确的管理和技术决策以及采取适当的纠正活动。
从软件生存周期模型中来看,人们常常直观的认为软件测试仅仅是软件生存周期中软件编码完成之后的一个或几个阶段。而实际上,软件测试本身也是一个过程,它可以进一步具体的分成若干个阶段性活动,如:测试计划、测试设计、测试执行、测试总结。对测试过程的度量必须涉及到测试过程中的各个阶段的度量,包括规模、工作量、进度、缺陷等等。下面着重介绍下测试设计和测试执行阶段与效率和质量相关的度量。
(1)测试设计
软件测试设计阶段主要工作是测试用例的设计与开发,在这个阶段可度量项包括:
● 用例生产率
用例生产率 = 测试用例个数(个数)/ 设计用例的时间(小时)。
在项目组中度量时,既可以得到每个项目组成员的用例生产率,从而来衡量其生产率;也可以得到项目组的用例生产率,与公司的度量财富库中的用例生产率进行比较,可得到自己项目组的整体水平。
● 用例质量
在用例写完进入测试执行阶段之前或是写用例的过程中,都会有对用例进行评审的过程,用例质量可以通过评审中发现的问题来评价。用例质量 = 评审问题个数 / 用例个数。
(2)测试执行
软件测试执行阶段,是在准备好的测试环境上依次执行各测试用例并详细记录每一步测试结果,提交缺陷记录的过程。在这个阶段可度量项包括:
● 用例执行率
用例执行率 = 执行的用例个数 / 执行测试的时间。通过这个派生度量即可以得到项目组每个成员的用例执行率,同样也可以得到项目组的平均用例执行率。
● 用例有效率
用例有效性 = 发现的缺陷个数 / 用例个数。用例有效性的可比性在项目之间不是很大,因为各个软件项目质量的好坏会直接影响到用例的有效性,若项目质量较好,则同样的用例个数发现的缺陷较少,若项目质量较差,则同样的用例个数发现的缺陷较多,但若在同一个项目中进行比较,还是有一定的可比性可言的。
● 缺陷发现率
缺陷发现率 = 缺陷个数 / 执行测试的时间。前面提到用例执行率可以看出项目组成员的工作效率,但并不能保证其质量,通过项目组成员各自发现的缺陷个数除以各自所花的时间,通过缺陷发现率这个指标来关注项目组成员的工作质量。
● 缺陷等级分布
对项目组发现的缺陷,按缺陷等级进行分类统计,得到系统的各个等级的缺陷分布情况。
● 模块缺陷率
模块缺陷率 = 该模块发现的缺陷个数 / 该模块的用例个数。这样可以得到它与其他模块的横向比较。