qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

测试驱动开发在系统中的设计实现及效能分析

 3.2.3 详细设计、编码、测试阶段

  对上述几个需求点进行详细设计、编码和测试。最后对单元模块的具体实现方案如下:

图1 测试驱动单元模块的基本结构

  如图所示,整个系统分为两个部分:实现产品功能等需求的“应用模块(Application Module)”、实现测试驱动开发的“测试模块(Test Mt,dule)”。

  测试模块又分为3个子模块:输入子模块、输出子模块、处理子模块。“输入子模块”主要是接收外部的一些命令;“处理子模块”主要是接收已经经过“输入子模块”过滤、解析的命令,然后与应用模块进行信息的查询、收集、控制等操作,再把一些信息传递给“输出予模块”;“输出子模块”就接收“处

  理子模块”传递过来的信息,并把它呈现出来。由这个测试模块来实现前面总结四个方面的17条测试驱动需求。比如“自动化测试脚本支持”这一需求:如果后期测试人员要做一个自动化测试,就可以在测试模块的界面输入测试脚本,这些测试脚本由“输入子模块”进行处理后传达到“处理子模块”;“处理子模块”对这些脚本逐条进行解析转化成应用模块“认识”的命令,然后去向应用模块进行查询信息、对应用模块进行控制下达操作命令......这样处理完之后,把一些需要输出的信息,比如执行结果、成功失败等信息传递给“输出子模块”;最后经过“输出子模块”把结果、信息给测试人员看。这样设计的优点在于,不管应用如何升级、如何改变,只要应用模块与测试模块之间的接口不变,这个测试模块就都可以起作用。

  4、效果分析

  该项目总代码行为15.3K,其中测试驱动代码行为6.6K(测试模块的代码量),测试驱动代码占总代码的43%。

  (1)通过测试驱动开发可以提高测试效率、定位bug效率

  用“测试并定位1个bug所需人天”作为测算指标,这个指标的计算公式。3 o如下:(测试所投入的人员天数+定位bug所投人人员天数)/测试阶段所发现的全部bug,得到“测试并定位1个bug所需人天”这个指标。选取了一个没有实现测试驱动的项目作比较,该项目的测试效率:

  测试并定位1个问题所需人天=2.93人天

  而在这个实现了测试驱动的项目的系统测试投入人天及定位bug投人人天共368人时=46人天,共发现并定位bu932个,测试效率如下:

  测试并定位1个问题所需人天=46人天/32=1.44人天

  这个测试效率明显提高很多,在发现的32个bug中,大部分的bug是可以根据系统所提供的测试驱动手段很快定位的。

  (2)通过测试驱动开发可以降低测试成本

  开发设计的投入成本相比测试成本是要低的,开发投入的成本主要是人员、PC机;而测试投入的成本主要是人员、设备,设备是测试成本中占比重最大的。测试环境要包括所有组网设备、还有测试所需的设备,都是非常昂贵的。对于没有实现测试驱动开发的项目,测试人员往往需要自行开发一些测试工具,对系统进行测试,而且首先要先熟悉该系统去了解开发人员的设计和开发思路,然后才能进行完善的测试,而这是很浪费时间和人力。而实现测试驱动开发的项目就可以把这一步简化为只需要测试人员写测试脚本、甚至可以把这一步完全略去。所以可以通过前期测试驱动的投入来降低后期测试所需要投入的成本,效果非常明显。

  (3)通过测试驱动开发可以降低“不可重现/随机重现”bug的比例

  实践证明,通过测试驱动开发,大大降低了“不可重现/随机重现”bug的比例。这类问题是系统的很大隐患。通过测试驱动开发,因为很多会出现问题的地方都打印了相关信息、同时也提供很多方法来进一步的定位控制,大部分以前认为是“不可重现/随机重现”的bug都可以抓到蛛丝马迹,最后来定位和解决。

  (4)通过测试驱动开发可以提高开发设计文档的质量

  以前系统开发的模式,是开发人员进行开发,测试人员根据开发人员完成的各种文档进行各类测试计划的撰写、进行测试,这样的模式下,开发与测试是完全独立甚至对立的立场。在整个测试驱动项目开发的过程中,对于测试驱动需求的实现都是由开发人员来完成的,这样就有两方面优点:

  (1)促使开发人员从测试的角度来考虑问题、来进行设计。

  (2)当开发人员在对测试需求进行设计时,也会促使他对已经完成的sRS、HLD等设计文档进一步的进行反思,进而促进设计文档的正确性、完备性,提高前期设计的质量。经验证明,大型软件的问题多是前期设计不当引起的,所以提高前期设计的质量尤为关键。

 摘要:介绍测试驱动开发(TDD),以某通讯系统中测试驱动开发实现为例,从理论与实践上论证了在复杂系统中测试驱动开发可提高测试的效率,在整体上确保系统的安全可靠性。

  关键词:软件测试;TDD;测试驱动开发;cMM;软件能力成熟度;自动测试脚本;

  1、简介

  为了在软件发布前发现尽量多的问题,在开发结束后进行测试,进而为了在软件开发的前期发现尽量多的问题,而在软件开发的过程中引入测试。随着软件产业的迅猛发展,尤其在通讯、航空、国防等大型复杂系统的研制中,对系统的可靠性、安全性要求尤为重要,为了提高系统的开发效率,在软件开发的概念阶段就把测试作为需求进行设计,即测试优先的理念,也就是测试驱动开发。

  2、测试是确保软件质量的重要手段

  软件工程的发展提出在软件开发的过程中、在开发的每一个阶段对软件的质量进行监控,以便生产出高质量的软件产品,测试体现在软件开发的每一个阶段中,这也就是CMM所强调的一种理念。现代的软件开发工程是将整个软件开发过程明确的划分为几个阶段,将复杂问题具体按阶段加以解决。在软件的整个开发过程中,可以对每一阶段提出若干明确的监控点,作为各阶段目标实现的检验标准,从而提高开发过程的可见度和保证开发过程的正确性。实践证明,软件的质量不仅是体现在程序的正确性上,它与编码以前所做的需求分析,软件设计密切相关。因此,为了保证软件的质量,应该着眼于整个软件生存期,特别是着眼于编码以前的各开发阶段的工作。广义的软件测试由确认、验证、测试三个方面组成:

  (1)确认:评估将要开发的软件产品是否是正确无误、可行和有价值的。包含了对用户需求满足程度的评价,确保一个待开发软件是正确无误的,是对软件开发构想的检测。

  (2)验证:是检测软件开发的每个阶段、每个步骤的结果是否正确无误,是否与软件开发各阶段的要求或期望的结果相一致。验证意味着确保软件开发过程的正确无误。

  (3)测试:与普通的测试概念统一。通常经过单元测试、集成测试、系统测试三个环节。

  在整个软件生存期,确认、验证、测试相辅相成,分别有其侧重的阶段。确认无疑会产生验证和测试的标准,而验证和测试通常又会帮助完成一些确认,特别是在系统测试阶段。

  3、测试驱动开发

  3.1 测试驱动开发的提出

  测试驱动开发的理念强调把测试作为开发过程的一个主要部分,比如在软件的需求阶段,把测试作为需求的一部分,在软件开发的每一个阶段,都有一部分的设计和代码是专门为测试而服务的。这样在编码之前先设计测试方案,从测试的角度验证设计,推导设计,同时将测试方案作为编码的准绳,实时验证其正确性。

  下面具体介绍某无线网通讯系统中实现测试驱动开发的过程,以及取得的结果。

  3.2 测试驱动开发设计实现

  在需求分析阶段集合开发设计人员、测试人员讨论测试需求,然后在该项目开发的后续每一个阶段来对这些测试驱动需求进行设计,最终在编码阶段实现并在测试阶段测验其效果。

  3.2.1 需求分析阶段

  在需求分析阶段通过综合讨论与论证,确定了以下4个方面的测试需求:

  (1)可观察性需求:开发出来的软件是可观察的。比如发生故障时会以告警、调试信息等方式以供查看。

  (2)可控制性需求:开发出来的软件是可以控制的,并且不影响其正常运行。比如说当发生某一严重故障时,可以通过使用某一预留的功能开关来定位、解决。

  (3)协议测试需求:要满足该软件特定协议的规定和要求。比如要对这个协议进行测试需要一些特定的观察点,那这个软件就可以把这些观察点的值输出来以供对比、甚至可以自行比较并在最后输出一个是否符合该协议的测试结果。

  (4)业务测试驱动需求:要满足特定业务流程的规定和要求,把一些特定的阶段输出来以供对比是否符合标准流程、甚至可以自行比较并在最后输出一个是否符合该标准流程的测试结果。

 3.2.2 概要设计阶段

  在概要设计阶段对以上四个方面进行设计,并且讨论具体的实施投入产出比,最后确定了以下17个具体的测试驱动实施方案:

  (1)可观察性需求

  ·告警:主要是提供一些预警的信息。可以分为几个级别:致命告警、严重告警、重要告警、次要告警等。

  ·日志:主要是把一些运行过程中出现的一些情况等记录下来,可以在出现问题时供查看。

  ·调试信息:系统自己打印出来的一些信息,可以给用户查看系统现在运行的状况。调试信息要注意可读性、实用性、规范性。

  ·出错信息:系统发现哪个地方出错,就给出信息以便用户参考。

  ·统计信息:主要是一些系统相关的统计信息,如统计在线的用户个数、掉线的用户个数等等。

  ·资源使用情况统计信息:查看系统一些资源的使用情况,如某个现在剩余端口数等信息。

  ·CPu占用率统计信息:查看系统cPu占用率,比如使用嵌入式操作系统pS0s或者VxWorks,可以提供手段来查看某个进程、各个进程占用CPU的情况。

  ·接口消息打印等:系统内部各个子模块之问的接口消息可以打印出来,检查是否正确。

  (2)可控制性需求

  ·重定向功能:可以选择输出方式,例如把要打印到屏幕的信息,通过设置改为打印到某一文件。

  ·分级调试开关:调试信息分级,设置为某一调试级别就可以看到该级别下用户可以看到的调试信息;这样有助于定位问题、也有助于一些内部设计信息的保密陛。

  ·外部消息模拟:可以实现模拟外部消息的功能,这样就可以减少对外部的依赖性。

  ·自动化测试脚本支持:可以通过编写一些测试脚本,来进行一些自动化测试。

  (3)协议测试驱动需求

  ·协议报文打印:如协议一些关键字段的打印。

  ·协议各消息统计:统计某协议各类消息的数量,尤其是当要跟其他产品进行对接时这个功能很重要。

  (4)业务测试驱动需求

  ·接续跟踪:具体业务所需的功能,可以让用户很直观的看到系统处理的过程。

  ·状态迁移:具体业务所需的功能,比如该系统设计了一个状态机,那么通过打印状态迁移过程可以很明显的判断处理是否正确、问题出现在哪一步。

  ·分类的业务相关统计信息:可以根据不同业务类型来进行统汁,这样可以过滤掉一些所不需要的信息。


posted @ 2013-06-06 10:35 顺其自然EVO 阅读(249) | 评论 (0)编辑 收藏

软件测试管理中可能存在的问题及分析解决

 摘要:本文结合实践,主要探讨了在中小型软件企业中,在测试资源不是很充足的情况下的软件测试管理。文中前两部分简要介绍了软件测试管理及测试的范围,方法及重要性,之后对当前国内中小型软件企业在测试及测试管理中可能存在的问题进行了简单的介绍与分析,最后介绍了一些较好的解决方法。

  关键词:软件测试;测试管理;测试问题;管理体系

  1、引言

  随着IT技术的迅速发展,计算机在各行各业日益广泛的应用,软件产品的不断推出,计算机软件已经越来越深人到人们的生活中,人们对计算机软件质量的要求也就越来越高。如果软件存在故障,将可能造成人力、物力和财力的巨大浪费;如果软件的质量不高,其维护费用不仅将大大超过其开发费用,而且会使维护变得很困难,甚至将可能造成不可弥补的损失。

  软件测试是软件质量保证的关键步骤。美国质量保证研究所对软件测试的研究结果表明:越早发现软件中存在的问题,开发费用就越低;在编码后修改软件缺陷的成本是编码前的10倍,在产品交付后修改软件缺陷的成本是交付前的10倍;软件质量越高,软件发布后的维护费用越低。另外,根据对国际著名IT企业的统计,它们的软件测试费用占整个软件工程所有研发费用的50%以上。由此可见,为了保证软件产品的质量,必须对计算机软件进行测试。

  随着计算机硬件成本的不断下降,软件在整个计算机系统的成本中占有越来越高的比例,如何提高软件质量是整个计算机软件行业的重大课题。软件测试作为软件开发的一个重要环节,日益受到人们的重视。为了尽可能多地找出程序中的错误,生产出高质量的软件产品,加强对测试工作的组织和管理就显得尤为重要。

  由于软件测试至今仍令人捉摸不定,为确保测试工作的顺利进行,就要对其进行有效地管理。软件测试管理是一种活动,可以对各阶段的测试计划、测试案例、测试流程进行整理、跟踪、记录其结果,并将其结果反馈给系统的开发者和管理者。同时将测试人员发现的错误立刻记录下来,生成问题报告并对之迸行管理。所以采用软件测试管理方法可以为软件企业提供一个多阶段、逐步递进的实施方案。通过此管理方法,软件企业还可以用有限的时间和成木完成软件开发确保软件产品的质最,进一步提高计算机软件在市场上的竞争能力。

  一般应用过程方法和系统方法来建立软件测试管理体系,也就是把测试管理作为一个系统,对组成这个系统的各个过程加以识别和管理,以实现设定的系统目标。同时要使这些过程协同作用、互相促进,从而使它们的总体作用大于各过程作用之和。其主要目标是在设定的条件限制下,尽可能发现和排除软件缺陷。

  但是当前,中国软件企业在软件测试方面与国际水准仍存在较大差距。首先,在认识上重开发、轻测试,没有认识到软件项目的如期完成不仅取决于开发人员,更取决于测试人员;其次,在管理上随意、简单,没有建立有效、规范的软件测试管理体系;另外,缺少自动化工具的支持,大多数企业在软件测试时并没有采用软件测试管理系统。所以对国内软件企业来说,不仅要提高对软件测试的认识,同时要建立起完善的软件测试管理体系。

  2、软件测试及测试管理的范围

  2.1 测试的范围

  下面主要就测试的参与者,测试要素,测试开始时应确定的工作,测试过程简要介绍软件测试的工作范围。

  参与者

  ● 用户方代表

  ● 软件最终使用者

  ● 软件开发人员

  ● 软件测试人员

  ● 高层经理的支持

  ● 过程保证人员(SQA)

  测试要素

  ● 正确性:数据输入,过程处理和输出的正确性(IPO)。

  ● 文件完整性:文件被正确使用,恢复和存储的数据正确。

  ● 授权:特殊的授权可以执行一个特殊的操作。

  ● 进程追踪:当进程运行中,程序有能力证实进程在正常工作。

  ● 系统运行的连续性:当有非致命性问题发生后,系统有能力继续运行关键的任务。

  ● 服务水平:系统有紧急情况发生时,要求程序的输出结果不经或进行简单的处理后就可以直接使用。

  ● 权限控制:防止系统被误用(意外或者有意的)。

  ● 一致性:确保最终设计和用户需求完全一致。

  ● 可靠性:在规定的时间内都可以正常运转。

  ● 易于使用:多数人均感觉易于使用。

  ● 可维护性:可以很容易的定位问题,并且进行修改。

  ● 可移植性:数据或者程序易于移至到其它系统上。

  ● 耦合性:系统中的组件可以很容易的联接。

  ● 性能:系统资源的占用率,响应时间,并发处理。

  ● 操作性:易于操作(Operator)。

  测试开始时应确定的工作

  ● 需求阶段

    → 确定测试策略

    → 确定收集了足够的需求

    → 产生功能性的测试用例

  ● 设计阶段

    → 确定设计和需求之间的联系

    → 确定进行了足够的设计

    → 产生结构和功能的测试用例

 ● 编码阶段

    确定和设计之间的联系

    确定拥有执行的足够条件

    产生结构和功能的测试用例

  ● 测试阶段

    确定设计了足够的测试用例

    测试应用系统已经完成

    关键资源已经到位

  ● 安装阶段

    将测试完成的系统变为产品

  ● 维护阶段

    修改和重新测试

    软件的测试过程

  ● 估算:对软件工作量的估算;对软件系统的状况的评估。

  ● 测试计划:详细的描述怎样能成功的完成测试工作,其中应包含必须的资源和实施计划。

  ● 需求测试:在软件开发的所有阶段进行测试,测试应该尽早,在需求和设计阶段发现的缺陷修正的花费最小。

  ● 设计测试:给测试要素打分;分析测试要素;对设计进行评审;检查修改的部分。

  ● 编码测试:编码是否按照既有的标准进行,过程是否易于实践;是否编制了足够的文档。

  ● 测试总结:表示出目前项目的实际状况;明确测试所做的工作,给出系统的操作性能的评价,明确什么时候系统可以进行产品化的工作。

  ● 安装,交付测试:检验检查表和产品的正确性;使用测试标准去检验发生的问题。

  ● 维护阶段的测试:开发一些测试用例,预先发现一些问题;对用户进行培训。

  2.2 测试管理的范围

  软件测试管理要解决的课题是如何确保软件测试技术能在软件项目在软件生命内得到顺利实施,并产生预期的效果。按照管理的对象不同,软件测试管理大致分为软件测试团队组织管理、软件测试计划管理、软件缺陷(错误)跟踪管理以及软件测试件管理四大部分。

  软件测试团队组织管理通俗的讲就是测试团队应该如何组建以及测试人员管理。在实际项目开发中,我们常常看到有些单位忽视测试团队存在的意义,当要实施测试时,往往临时找几个程序员充当测试人员;也有些单位尽管认识到了组建测试团队的重要性,但在具体落实的时候往往安排一些毫无开发经验的行业新手去做测试工作,这常常导致测试效率的低下,测试人员对测试工作索然无味。一个好的测试团队首先要有好的带头人,他必须具有极为丰富的开发经验,对开发过程中常见的缺陷或错误了然于胸,此外,他还应具有亲和力和人格魅力。其次,测试团队还应有具备一技之长的成员,如对某些自动化测试工具运用娴熟或能轻而易举地编写自动化测试脚本。另外,测试团队还应有兼职成员。如验证测试实施过程中,同行评审是最常使用的一种形式,这些同行专家就属于兼职测试团队成员的范畴。测试团队里往往不乏缺乏开发经验软件新手,这部分人可以安排去从事交付验证或黑盒测试之类的工作。

  软件测试计划管理通俗地讲就是安排好测试流程。这部分内容具体涵盖软件测试策划、软件测试技术剪裁、测试进度管理、成本管理等几个部分。其中测试策划工作主要是指具体测试活动实施之前做好策划工作,如起草测试大纲以及测试计划;软件测试技术剪裁工作主要是指测试团队应根据软件项目的具体实际剪裁出所要实施的测试技术;测试进度管理工作主要是指排出各项测试的时间进度及人员安排,如有变动时应做相应调整;测试成本管理工作的内容即开列出测试活动中会涉及到的资源需求。

  软件缺陷(错误)跟踪管理通俗地讲就是确保发现的缺陷(错误)已经被开发团队纠正或处理过并且没有引入新的缺陷(错误)。具体来讲,当测试团队通过各种途径发现了文档或代码中的缺陷或错误以后,并不是交一份测试报告就草草了事,而是在递交报告以后继续督促开发团队及时关闭已知缺陷或错误(当然,如有必要应对这些缺陷、错误做严重程度排序,以便开发团队能视轻重缓急安排处理顺序)。当开发团队关闭了测试报告中的缺陷(错误)以后,测试团队还需验证开发团队在关闭过程中有没有引入新的错误。通常,这个过程称为回归测试。回归测试如发现问题,继续报开发团组,按上述流程循环,直至回归测试最终通过。

  软件测试件管理通俗地讲就是指努力建设好测试团队的财富库并对测试团队成员进行技能培训以帮助他们能使用好这个财富库。这里,财富库是指软件测试件。测试件(Testware,指测试工作形成的产品)是一个不常见到的词汇,它包括是测试团队在长期实践过程中逐步积累起来的经验教训、测试技巧、测试工具、规格文档以及一些经过少量修改能推广至通用的测试脚本程序。测试件管理工作做得越好,测试团队在实际测试过程中就能越少走弯路,测试团队内部的知识交流和传递就越充分,测试脚本或规格文档的重复开发工作也就能被有效地避免。软件测试件管理工作包括两部分,一是建设,另一个是培训。建设工作大抵是收集各类测试外文档、测试工具、测试脚本,也包括收集整理测试人员的会议发言、总结报告、技术心得等等。培训工作大抵是通过技术讲座、正式或非正式团队会议、印发学习资料等形式进行。

2.3 软件测试管理内容

  具体的测试管理内容有:

  ● 测试方案管理:单元测试、集成测试和产品测试的测试计划的录入、修改、删除、查询和打印。

  ● 测试案例管理

    测试案例的增、删、改、拷贝和查询;

    测试案例测试情况的管理,如测试状态包括:未测试、测试中、已测试;

    测试结果分为:通过、未实现、存在问题等;

    测试案例输人、编号和归档。

  ● 测试流程管理:测试进度管理;测试流程标识;测试日志及状态报告。

  ● 问题报告管理:问题报告处理流程(问题报告、整改报告)、实现问题报告与测试案例的关联。

  ● 测试报告管理:生成单元测试、集成测试和产品测试的测试报告。

  除了以上这些,在侧试管理过程中还应对人员和环境资源进行管理。

  3、测试及测试管理中的问题及分析

  通过以上的简单总结与分析,可以看到软件测试及测试管理的重要性,及其复杂、广泛的组织管理工作,所以在实施起来,难免与理论有些出入。另外,国内的软件企业大多起步晚,技术基础薄弱,应用与管理经验缺乏,在测试上更是如此。于是国内的一些中小型的软件企业,在软件测试方面存在诸多问题,不仅与理论要求相差甚远,与实际的应用需求也相差很多。下面将简要介绍与分析当前国内中小型软件企业在测试及测试管理中存在的问题和问题原因,并在之后提出一些解决办法。

  3.1 软件本身的复杂性与企业自身的不足

  这里复杂性包括软件用户需求的复杂与难确定性,软件开发过程的组织管理的难控制性等,使得软件开发过程必然会存在诸多问题,开发出的产品也必然存在一些缺陷与不足。而由于生产与管理经验的不足,缺乏高效的开发与测试团队,往往是开发人员又是测试人员,或测试人员质量管理;缺乏有效的测试技术,代码走查室最常用的方法;测试开始较晚,往往在开发完成之后;对用户反馈信息缺乏整理总结等;使得不仅难以控制产品的缺陷数量,而且对于缺陷的定位与修补也很难到位。

  3.2 测试的特性

  3.2.1 测试是不完全的(测试不完全)

  由于软件需求的不完整性、软件逻辑路径的组合性、输入数据的大量性及结果多样性等因素,哪怕是一个极其简单的程序,要想穷尽所有逻辑路径,所有输入数据和验证所有结果是非常困难的一件事情。

  3.2.2 测试具有免疫性(软件缺陷免疫性)

  软件缺陷与病毒一样具有可怕的“免疫性”,测试人员对其采用的测试越多,其免疫能力就越强,寻找更多软件缺陷就更加困难。在软件测试中采用单一的方法不能高效和完全的针对所有软件缺陷,因此软件测试必须采用不同的测试方式和测试数据,应该尽可能的多采用多种途径进行测试。

  3.2.3 测试是“泛型概念”(全程测试)

  如果单纯的只将程序设计阶段后的阶段称之为软件测试的话,需求阶段和设计阶段的缺陷产生的放大效应会加大。这非常不利于保证软件质量。需求缺陷、设计缺陷也是软件缺陷,记住“软件缺陷具有生育能力”。软件测试应该跨越整个软件开发流程。需求验证(自检)和设计验证(自检)也可以算作软件测试(建议称为:需求测试和设计测试)的一种。软件测试应该是一个泛型概念,涵盖整个软件生命周期,这样才能确保周期的每个阶段禁得起考验。同时测试本身也需要有第三者进行评估(信息系统审计和软件工程监理),即测试本身也应当被测试,从而确保测试自身的可靠性和高效性。

 3.2.4 软件缺陷具有空间聚集性(80-20 原则)

  80%的软件缺陷常常生存在软件20%的空间里。这个原则告诉我们,如果你想使软件测试有效地话,记住常常光临其高危多发“地段”。在那里发现软件缺陷的可能性会大的多。这一原则对于软件测试人员提高测试效率及缺陷发现率有着重大的意义。聪明的测试人员会根据这个原则很快找出较多的缺陷而愚蠢的测试人员却仍在漫无目的地到处搜寻。

  80-20 原则的另外一种情况是,我们在系统分析、系统设计、系统实现阶段的复审,测试工作中能够发现和避免80%的软件缺陷,此后的系统测试能够帮助我们找出剩余缺陷中的80%,最后的5%的软件缺陷可能只有在系统交付使用后用户经过大范围、长时间使用后才会曝露出来。因为软件测试只能够保证尽可能多地发现软件缺陷,却无法保证能够发现所有的软件缺陷。

  3.2.5 为效益而测试

  为什么我们要实施软件测试,是为了提高项目的质量效益最终以提高项目的总体效益。为此我们不难得出我们在实施软件测试应该掌握的度。软件测试应该在软件测试成本和软件质量效益两者间找到一个平衡点。这个平衡点就是我们在实施软件测试时应该遵守的度。单方面的追求都必然损害软件测试存在的价值和意义。一般说来,在软件测试中我们应该尽量地保持软件测试简单性,切勿将软件测试过度复杂化。

  3.2.6 缺陷的必然性

  软件测试中,由于错误的关联性,并不是所有的软件缺陷都能够得以修复。某些软件缺陷虽然能够得以修复但在修复的过程中我们会难免引入新的软件缺陷。很多软件缺陷之间是相互矛盾的,一个矛盾的消失必然会引发另外一个矛盾的产生。比如我们在解决通用性的缺陷后往往会带来执行效率上的缺陷。更何况在缺陷的修复过程中,我们常常还会受时间、成本等方面的限制因此无法有效、完整地修复所有的软件缺陷。因此评估软件缺陷的重要度、影响范围,选择一个折中的方案或是从非软件的因素(比如提升硬件性能)考虑软件缺陷成为我们在面对软件缺陷时一个必须直面的事实。

  3.3 测试组织管理不专业

  1、测试人员不独立于开发者,测试人员独立于开发者的程度将影响测试结果。

  人很容易用自己已经非常仔细地做过测试来欺骗自己,开发人员做测试容易受到个人的习惯性想法的影响,程序中可能包含由于程序员对问题的叙述或说明的误解而产生的错误。如果是这种情况,当开发人员测试自己的程序时,往往还会带着同样的误解致使问题难以发现。开发和测试是两种不同的活动,开发人员对自己的程序进行一定的审查、调试是必要的,但是一般情况下还需要另外的专业测试者进行测试。不过,由于有的企业中,人力有限,或者认为没有足够的资源或理由支持一支测试队伍,有时不得不由开发人员测试;那么,开发者对自己的程序的测试需要注意许多问题,或者应由另外的开发者对自己的程序进行测试。

  2、测试时间安排往往计划不周,测试计划有时受制于开发计划。

  3、测试等级以及在那个等级上的测试时间往往选择不当。

  4、测试辅助设备和测试工具将影响开发者的测试效率及测试彻底性。

  5、测试策略文档的普遍缺失。

  6、测试范围的确认经常被其他文档或经验所取代。

  7、测试任务应该像BUG 一样有明确的分级,不同类型的测试应该有相应的测试用例集合与之对应。

  8、关键路径概念在测试规划时容易被项目经理弱化。

  9、测试用例不科学,测试用例在实际中没有起多大作用;在实际测试时根本没有按用例执行;往往测试执行后没有把新的用例补充到用例库中。

  3.4 测试人员的影响

  1)测试人员入门容易学习困难,无章可循;人员增加可能有重复工作。

  2)测试人员对现实应用与需求的理解可能有偏差。

  3)测试人员可能对测试存在一些不正确的看法和错误的态度,如下:

  (1) 认为测试工作不如设计和编码那样容易取得进展难以给测试人员某种成就感;

  (2) 以发现软件错误为目标的测试是非建设性的,甚至是破坏性的,测试中发现错位是对责任者工作的一种否定;

  (3) 测试工作枯燥无味,不能引起人们的兴趣;

  (4) 测试工作是艰苦而细致的工作;

  (5) 对自己编写的程序盲目自信,在发现错误后,顾虑别人对自己的开发能力的看法。

  4)提交以后对用户反馈信息缺乏及对缺乏足够的重视,对于有大量用户有持久生命力的软件产品(如Microsoft Office),用户反馈信息较全面,便于开发和测试人员进行软件的修补和维护;而一些中小软件企业的产品却远远无法和Microsoft Office 相比;于是可能缺乏足够的用户反馈信息,或没有足够的时间或人力处理用户反馈信息。

  5)开发及测试人员工作习惯,编程习惯,测试习惯等也影响测试的效果;由于测试人员短期的学习与培训,一般能提高的只是方法和技巧;而其自身能力与习惯可能的负面影响却一时难以消除。

 4、测试管理问题的解决

  4.1 建立软件测试管理体系

  建立软件测试管理体系的主要目的是确保软件测试在软件质量保证中发挥应有的关键作用,包括以下工作:

  软件产品的监视和测量:对软件产品的特性进行监视和测量,主要依据软件需求规格说明书,验证产品是否满足要求。所开发的软件产品是否可以交付,要预先设定质量指标,并进行测试,只有符合预先设定的指标,才可以交付。

  对不符合要求的产品的识别和控制:对于软件测试中发现的软件缺陷,要认真记录它们的属性和处理措施,并进行跟踪,直至最终解决。在排除软件缺陷之后,要再次进行验证。

  产品设计和开发的验证:通过设计测试用例对需求分析、软件设计、程序代码进行验证,确保程序代码与软件设计说明书的一致,以及软件设计说明书与需求规格说明书的一致。对于验证中发现的不合格现象,同样要认真记录和处理,并跟踪解决。解决之后,也要再次进行验证。

  软件过程的监视和测量:从软件测试中可以获取大量关于软件过程及其结果的数据和信息,它们可用于判断这些过程的有效性,为软件过程的正常运行和持续改进提供决策依据。

  一般应用过程方法和系统方法来建立软件测试管理体系,也就是把测试管理作为一个系统,对组成这个系统的各个过程加以识别和管理,以实现设定的系统目标。同时要使这些过程协同作用、互相促进,从而使它们的总体作用大于各过程作用之和。其主要目标是在设定的条件限制下,尽可能发现和排除软件缺陷。测试系统主要由下面6 个相互关联、相互作用的过程组成:测试规划、测试设计、测试实施、配置管理、资源管理和测试管理;确定这些过程的顺序和相互作用,前一过程的输出是后一过程的输入。其中,配置管理和资源管理是这些过程的支持性过程,测试管理则对其他测试过程进行监视、测试和管理;确定这些过程所需的准则和方法,一般应制订这些过程形成文件的程序,以及监视、测量和控制的准则和方法;确保可以获得必要的资源和信息,以支持这些过程的运行和对它们的监测;监视、测量和分析这些过程;实施必要的改进措施。

  4.2 建立配置管理系统,规范项目管理流程

  建立配置管理系统 CVS,CVS 的全称是Current Version Control。在软件质量体系的诸多支持活动中,配置管理系统处在支持活动的中心位置,它有机地把其它支持活动结合起来,形成一个整体,相互促进,相互影响,有力地保证了质量体系的实施。建立公司配置管理系统很容易得到公司领导层的支持,几乎没人反对。更重要的是建立配置管理系统后测试人员的工作有了系统保证,测试工作的“矿藏资源”有了明确的位置,可以主动积极开展测试工作。

  4.3 测试过程分阶段执行

  将测试过程分成几个阶段执行,即:代码审查、单元测试、集成测试、确认测试和系统测试。

  单元测试是针对软件设计的最小单位-模块进行正确性检验的测试工作,其目的在于发现各模块内部可能存在的各种差错。在单元测试之后,需要按照设计时做出的结构图,将它们联结起来,进行集成测试。是检验所开发的软件是否按用户要求运行。确认测试应检查软件能否按合同要求进行工作,即是否满足软件需求说明书中的确认标准。软件开发完成后,还要与系统中其他部分配套运行,进行系统测试,包括恢复测试、安全测试、强度测试和性能测试等。

  4.4 做好过程管理

  过程管理须做好以下工作:分阶段设立里程碑,按里程碑计划工作和总结工作;加强审核,测试过程的中间结果要进行充分的审核;注重风险管理和规避风险,任何决定和过程都存在风险,尤其是质量好坏的风险,通过审核管理风险。

  4.5 制定成功的测试管理计划及测试计划

  一个成功的测试开始于一个全面的测试管理计划。因此在每次测试之前应做好详细的测试管理计划:

  首先,应该了解被测对象的基本信息,选择测试的标准级别,明确测试管理计划标识和测试管理项。在定义了被测对象的测试管理目标、范围后必须确定测试管理所使用的方法,即提供技术性的Ali 试管理策略和测试管理过程。在测试管理计划中管理者应该全面了解被测试对象的系统方法、语言特征、结构特点、操作方法和特殊需求等,以便确定必要的侧试环境,包括测试硬件/软件及测试环境的建立等等。而且.在测试管理计划中还应该制订一份详细的进度计划如:侧试管理的开始段、中间段、结束段及测试管理过程每个部分的负责人等。由于任何一个软件不可能没有缺陷、系统运行时不出现故障,所以在测试管理计划中还必须考虑到一些意外情况、也就是说,当问题发生时应如何处理。因为测试管理具有一定难度,所以对测试管理者应进行必要的测试设计、工具、环境等的培训。最后,还必须确定认可和审议测试管理计划的负责人员。

 还需要一个成功的测试计划,专业的测试必须以一个好的测试计划作为基础。尽管测试的每一个步骤都是独立的,但是必定要有一个起到框架结构作用的测试计划。测试的计划应该作为测试的起始步骤和重要环节。一个测试计划应包括:产品基本情况调研、测试需求说明、测试策略和记录、测试资源配置、计划表、问题跟踪报告、测试计划的评审、结果等等。

  4.6 测试人员及早介入

  测试人员应从软件生命周期的需求阶段就开始介入,这样可以在这些需求基础上生成一份测试计划,并将测试用例对应于需求。这样便于提高测试用例的有效性和可用性,并且方便测试用例的设计和管理。

  4.7 测试文件的使用

  在软件的需求分析阶段,就开始测试文件的编制工作,各种测试文件的编写应按一定的格式进行。测试文件的重要性表现在以下几个方面:

  a、验证需求的正确性:测试文件中规定了用以验证软件需求的测试条件,研究这些测试条件对弄清用户需求的意图是十分有益的。

  b、检验测试资源:测试计划不仅要用文件的形式把测试过程规定下来,还应说明测试工作必不可少的资源,进而检验这些资源是否可以得到,即它的可用性如何。如果某个测试计划已经编写出来,但所需资源仍未落实,那就必须及早解决。

  c、明确任务的风险:有了测试计划,就可以弄清楚测试可以做什么,不能做什么。了解测试任务的风险有助于对潜伏的可能出现的问题事先作好思想上和物质上的准备。

  d、生成测试用例:测试用例的好坏决定着测试工作的效率,选择合适的测试用例是作好测试工作的关键。在测试文件编制过程中,按规定的要求精心设计测试用例有重要的意义。

  e、评价测试结果:测试文件包括测试用例,即若干测试数据及对应的预期测试结果。完成测试后,将测试结果与预期的结果进行比较,便可对已进行的测试提出评价意见。

  f、再测试:测试文件规定的和说明的内容对维护阶段由于各种原因的需求进行再测试时,是非常有用的。

  g、决定测试的有效性:完成测试后,把测试结果写入文件,这对分析测试的有效性,甚至整个软件的可用性提供了依据。同时还可以证实有关方面的结论。

  4.8 测试团体的建设与测试人员的学习及培训

  要注重建立一支高效的测试团队,不利用各种方法对测试人员进行培训。测试人员须加强自身学习,测试人员必须和程序员、用户、市场人员、技术作者以及任何的可能为实现更好测试提供线索的人进行交流。充分利用网络,及时地不断地学习,充分利用软件测试的技巧等。

  4.9 经济的测试

  作为软件开发企业来说,投入人力,资金搞软件测试的最终目的还是离不开经济效益。而对与测试项目的管理也不能离开这个大前提。软件测试的经济效益主要来自以下两个方面。一是满足用户需求,提高产品的竞争力,最终提高产品的销售量。二是尽早发现缺陷,降低售后服务成本。而软件测试的最终目的就是使它带来的经济效益最大化。

  有时候用户应用机率越大的那些软件业务功能,应该越少有差错;对某些关键功能,应该不允许有差错;经常不用的,甚至基本不用的那些软件业务功能,则可以容忍它有差错,甚至有较多的差错。

  5、总结

  软件测试工作在软件开发过程中占有重要地位,在各种规模的软件的开发中,测试工作都必不可少。关于软件测试的研究与技术探讨可以说都有成熟的成果,但是在实际应用中,由于软件开发的时间的影响或软件项目中人员的不足等等各种因素的影响,使得在国内的中小型软件企业中软件测试工作存在一些问题,本文对这些问题进行了总结和分析,并提出了一些解决方法。


posted @ 2013-06-06 10:25 顺其自然EVO 阅读(771) | 评论 (0)编辑 收藏

Java中dom4j读取配置文件实现抽象工厂+反射

 在Java中也可以同Donet一样,将差异配置在配置文件里面。另外,我们采用下面的方式实现,将会更加便捷。

  逻辑描述:

  现在我们想在B层和D层加上接口层,并使用工厂。而我们可以将创建B和创建D看作是两个系列,然后就可以使用抽象工厂进行创建了。

  配置文件:beans-config.xml。service-class与dao-class分别对应两个系列的产品。子菜单中id对应接口的命名空间,class对应实现类的命名空间。

  1. [html] view plaincopyprint? 
  2.     <?xml version="1.0" encoding="UTF-8"?>   
  3.     <beans>   
  4.          <service-class>   
  5.             <service id="com.xxjstgb.drp.basedata.manager.ItemManager" class="com.xxjstgb.drp.basedata.manager.ItemManagerImpl" />   
  6.             <service id="com.xxjstgb.drp.flowcard.manager.FlowCardManager" class="com.xxjstgb.drp.flowcard.manager.impl.FlowCardManagerImpl" />   
  7.          </service-class>   
  8.          <dao-class>   
  9.             <dao id="com.xxjstgb.drp.basedata.dao.ItemDao" class="com.xxjstgb.drp.basedata.dao.ItemDao4OracleImpl" />   
  10.             <dao id="com.xxjstgb.drp.flowcard.dao.FlowCardDao" class="com.xxjstgb.drp.flowcard.dao.impl.FlowCardDaoImpl" />   
  11.          </dao-class>   
  12.     </beans>

  抽象工厂:BeanFactory。通过读取配置文件,取得相关对象,并将相关创建好的对象保存在Map中。

  1. [java] view plaincopyprint? 
  2.     package com.xxjstgb.drp.util;   
  3.        
  4.     import java.util.HashMap;   
  5.     import java.util.Map;   
  6.        
  7.     //dom4j   
  8.     import org.dom4j.Document;   
  9.     import org.dom4j.DocumentException;   
  10.     import org.dom4j.Element;   
  11.     import org.dom4j.io.SAXReader;   
  12.        
  13.     import com.xxjstgb.drp.basedata.dao.ItemDao;   
  14.     import com.xxjstgb.drp.basedata.manager.ItemManager;   
  15.     import com.xxjstgb.drp.flowcard.dao.FlowCardDao;   
  16.     import com.xxjstgb.drp.flowcard.manager.FlowCardManager;   
  17.        
  18.     /**  
  19.      * 抽象工厂,主要创建两个系列的产品  
  20.      * 1、Manager系列  
  21.      * 2、Dao系列产品  
  22.      * @author liuzhengquan  
  23.      *  
  24.      */   
  25.     public class BeanFactory {   
  26.            
  27.         private static BeanFactory instance=new BeanFactory();   
  28.            
  29.         //系统缺省配置文件名称   
  30.         private final String beansConfigFile="beans-config.xml";   
  31.            
  32.         //保存Dao相关对象   
  33.         private Document doc;   
  34.            
  35.         /*  
  36.          * key=配置文件中的id值  
  37.          * value=对应了该Id的对象  
  38.          */   
  39.         private Map serviceMap = new HashMap();//保存Service相关对象   
  40.         private Map daoMap = new HashMap();//保存Dao相关对象   
  41.            
  42.            
  43.         private BeanFactory(){   
  44.             try {   
  45.                 doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));   
  46.             } catch (DocumentException e) {   
  47.                 e.printStackTrace();   
  48.                 throw new RuntimeException();   
  49.             }   
  50.         }   
  51.            
  52.         public static BeanFactory getInstance(){   
  53.             return instance;   
  54.         }   
  55.            
  56.         /**  
  57.          * 根据产品编号取得Service系列产品  
  58.          * @param serviceId  
  59.          * @return  
  60.          */   
  61.         public synchronized Object getServiceObject(Class c){   
  62.             //如果存在相关对象实例,返回   
  63.             if(serviceMap.containsKey(c.getName())){   
  64.                 return serviceMap.get(c.getName());   
  65.             }   
  66.             Element beanElt=(Element)doc.selectSingleNode("//service[@id=\""+ c.getName() + "\"]");   
  67.             String className=beanElt.attributeValue("class");   
  68.             Object service=null;   
  69.                
  70.             try {   
  71.                 service=Class.forName(className).newInstance();   
  72.                    
  73.                 //将创建好的对象放到Map中   
  74.                 serviceMap.put(c.getName(), service);   
  75.             } catch (Exception e) {   
  76.                 throw new RuntimeException();   
  77.             }   
  78.             return service;   
  79.         }   
  80.            
  81.         /**  
  82.          * 根据产品编号取得Dao系列产品  
  83.          * @param daoId  
  84.          * @return  
  85.          */   
  86.         public synchronized Object getDaoObject(Class c){   
  87.             //如果存在相关对象实例,返回   
  88.             if(daoMap.containsKey(c.getName())){   
  89.                 return daoMap.get(c.getName());   
  90.             }   
  91.             Element beanElt=(Element)doc.selectSingleNode("//dao[@id=\""+c.getName()+"\"]");   
  92.             String className=beanElt.attributeValue("class");   
  93.             Object dao=null;   
  94.                
  95.             try {   
  96.                 dao=Class.forName(className).newInstance();   
  97.                    
  98.                 //将创建好的对象放到Map中   
  99.                 daoMap.put(c.getName(), dao);   
  100.             } catch (Exception e) {   
  101.                 throw new RuntimeException();   
  102.             }   
  103.             return dao;   
  104.         }   
  105.            
  106.            
  107.         /**  
  108.          * 测试  
  109.          * @param args  
  110.          */   
  111.         public static void main(String[] args){   
  112.             ItemManager itemManager=(ItemManager)BeanFactory.getInstance().getServiceObject(ItemManager.class);   
  113.             System.out.println("itemManager"+itemManager);   
  114.                
  115.             ItemDao itemDao=(ItemDao)BeanFactory.getInstance().getDaoObject(ItemDao.class);   
  116.             System.out.println("itemDao:"+itemDao);   
  117.                
  118.             FlowCardManager flowCardManager=(FlowCardManager)BeanFactory.getInstance().getServiceObject(FlowCardManager.class);   
  119.             //FlowCardManager flowCardManager=new FlowCardManagerImpl();   
  120.             System.out.println(flowCardManager);   
  121.                
  122.             FlowCardDao flowCardDao=(FlowCardDao)BeanFactory.getInstance().getDaoObject(FlowCardDao.class);   
  123.             //FlowCardDao flowCardDao=new FlowCardDaoImpl();   
  124.             System.out.println("flowCardDao:"+flowCardDao);   
  125.         }   
  126.            
  127.     }

  运行结果:

  总结:

  通过抽象工厂+反射的实现,调用层就可以只认识接口,而无须与具体实现打交道,实现了解耦合。同时,由于配置文件里面是接口和实现的命名空间,我们就可以用相应接口的.class属性,点出命名空间,将配置文件的id和class都以键值对的形式配置在Map中,实现反射。

posted @ 2013-06-06 10:23 顺其自然EVO 阅读(176) | 评论 (0)编辑 收藏

java工程师之路

 在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了。但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平。

  Java程序员

  Java,设计而又非常精巧的语言。学习Java,须从Java开发环境开始,到Java语法,再到Java的核心API。

  1、Java开发入门:Java开发环境的安装与使用,包括JDK命令、EclipseIDE、Linux下Java程序的开发和部署等。

  2、Java语法基础:基于JDK和Eclipse环境,进行Java核心功能开发,掌握Java面向对象的语法构成,包括类、抽象类、接口、最终类、静态类、匿名类、内部类、异常的编写。

  3、Java核心API:基于JDK提供的类库,掌握三大核心功能:

  A)Java核心编程:包括Java编程的两大核心功能——Java输入/输出流和多线程,以及常用的辅助类库——实体类、集 合类、正则表达式、XML和属性文件。

  B)Java图形编程:包括Sun的GUI库AWT(Java2D、JavaSound、JMF)和Swing,IBM和GUI库SWT和Jface;

  C)Java网路编程:Applet组件编程,Socket编程,NIO非阻塞Socket编程、RMI和CORBA分布式开发。

  4、Java高级特性:掌握JDK1.4、JDK5.0、JDK6.0中的Java高级特性,包括反射、泛型、注释,以及java高级特性——自动装箱和拆箱、枚举类、可变参数、可变返回类型、增强循环、静态导入等。

  JavaEE初级软件工程师

  JSF框架开发技术

  配置文件(页面导航、后台Bean)、JSF组件库(JSF EL语言、HTML标签、事件处理、)、JSF核心库(格式转换、输入验证、国际化)

  Javaweb核心开发技术

  开发环境(Eclipse、Linux)

  三大组件(JSP、JavaBean、Servlet)

  扩展技术(EL、JSTL、Taglib)

  网页开发技术

  HTML、XML、CSS、JavaScript、AJAX

  数据库设计技术

  SQLMySqlOracle、SQLServer、JDBC

  Web服务器(Tomcat/Jetty/Resin/JBossWeb)

  JavaWeb核心技术:

  JavaWeb项目开发的全过程可以分解为:

  网页开发+数据库设计——>JavaWeb项目开发,其中,javaWeb由6项基本技术组成:JSP+JavaBean+Servlet+EL+JSTL+Taglib,而JSF正是将这6种技术进行有机结合的技术框架。

  JavaEE中级软件工程师

  四种经典架构SSH1、SSI1、SSH2、SSI2

  Struts1表现层框架

  入门配置、核心组件、标签库、国际化、数据检验、数据库开发、Sitemesh集成、集成Hibernate/iBATIS

  Struts2表现层框架

  入门配置、核心组件、标签库、国际化、数据校验、Sitemesh集成转换器、拦截器、集成Hibernate/iBATIS

  Spring业务层框架

  入门配置、IoC容器、MVC、标签库、国际化、数据校验、数据库开发

  Hibernate持久层框架

  MySQL、Oracle、SQLServer iBATIS持久层框架

  MySQL、Oracle、SQLServer

  Web服务器(Tomcat/Jetty/Resin/JBossWeb)


Java高级软件工程师

  javaWeb开源技术与框架

  工作流、规则引擎搜索引擎、缓存引擎 、任务调度、身份认证报表服务、系统测试、集群、负载平衡、故障转移

  JavaWeb分布式开发技术

  JTA(Java事物管理)

  JAAS(Java验证和授权服务)

  JNDI(Java命名和目录服务)

  JavaMail(Java邮件服务)

  JMS(java信息服务)

  WebService(web服务)

  JCA(java连接体系)

  JMS(java管理体系)

  应用服务器(JBossAS/WebLogic/WebSphere)

  JavaEE系统架构师

  面向云架构(COA)

  COA、SaaS、网格计算、集群计算、分布式计算、云计算

  面向资源架构(ROA)

  ROA、RESI

  面向web服务架构(SOA)

  WebService、SOA、SCA、ESB、OSGI、EAI

  Java设计模式

  创建式模式:抽象工厂/建造者/工厂方法/原型/单例

  构造型模式:适配器/桥接/组合/装饰/外观/享元/代理

  行为型模式:责任链/命令/解释器/迭代子/中介者/备忘录/观察者/状态/策略/模板方法/访问者

  Java与UML建模

  对象图、用例图、组件图、部署图、序列图、交互图、活动图、正向工程与逆向工程

  CTO首席技术官

  发展战略

  技术总监

  团队提升

  团队建设

  项目管理

  产品管理

posted @ 2013-06-06 10:22 顺其自然EVO 阅读(293) | 评论 (0)编辑 收藏

java 静态方法和实例方法的区别

 静态方法和实例方法的区别主要体现在两个方面:

  在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。

  静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。

  下面几个例子展示了这一区别。

  1、调用静态方法示例。

<SPAN style="FONT-SIZE: 18px"><STRONG>//-----------hasStaticMethod.java-----------------
public class hasStaticMethod{
//定义一个静态方法
public static void callMe(){
  System.out.println("This is a static method.");
}
}
 
下面这个程序使用两种形式来调用静态方法。
//-----------invokeStaticMethod.java-----------------
public class invokeStaticMethod{
  public static void main(String args[]){
  hasStaticMethod.callMe();  //不创建对象,直接调用静态方法   
  hasStaticMethod oa = new hasStaticMethod();   //创建一个对象
  oa.callMe();      //利用对象来调用静态方法
}
} </STRONG></SPAN>

  程序两次调用静态方法,都是允许的,程序的输出如下:

  This is a static method.This is a static method.

  允许不创建对象而调用静态方法,是Java为了减少程序员调用某些常用方法时的麻烦,而允许程序员按照传统的C语言中使用函数的方式来使用方法。典型的例子是前面某些程序中使用"Math.ramdon()"来获取随机数。

  还有一个很典型的代表就是数组的处理工具Arrays

  2、静态方法访问成员变量示例。

<SPAN style="FONT-SIZE: 18px"><STRONG>//-----------accessMember.java-----------------
class accessMember{
private static int sa; //定义一个静态成员变量
private int ia;  //定义一个实例成员变量
//下面定义一个静态方法
static void statMethod(){
  int i = 0;    //正确,可以有自己的局部变量sa = 10;  
  //正确,静态方法可以使用静态变量
  otherStat(); 
  //正确,可以调用静态方法
  ia = 20;   //错误,不能使用实例变量
  insMethod();  //错误,不能调用实例方法
}
static void otherStat(){}
//下面定义一个实例方法
void  insMethod(){
  int i = 0;    //正确,可以有自己的局部变量
  sa = 15;    //正确,可以使用静态变量
  ia = 30;    //正确,可以使用实例变量
  statMethod();   //正确,可以调用静态方法
}
} </STRONG></SPAN>

  本例其实可以概括成一句话:静态方法只能访问静态成员,实例方法可以访问静态和实例成员。之所以不允许静态方法访问实例成员变量,是因为实例成员变量是属于某个对象的,而静态方法在执行时,并不一定存在对象。同样,因为实例方法可以访问实例成员变量,如果允许静态方法调用实例方法,将间接地允许它使用实例成员变量,所以它也不能调用实例方法。基于同样的道理,静态方法中也不能使用关键字this。 main()方法是一个典型的静态方法,它同样遵循一般静态方法的规则,所以它可以由系统在创建对象之前就调用。





posted @ 2013-06-06 10:17 顺其自然EVO 阅读(153) | 评论 (0)编辑 收藏

高效SQL语句必杀技

     摘要: Predicate Information (identified by operation id):---------------------------------------------------   4 - filter(LNNVL("OBJECT_ID"=69450))   5 - access("OWNER"='SYSTEM') &n...  阅读全文

posted @ 2013-06-06 10:15 顺其自然EVO 阅读(2183) | 评论 (0)编辑 收藏

百万连接测试之方法篇

 在上一篇中我们讲述了百万连接的测试过程及出现的问题和解决办法,有同学对其中的测试方法也有兴趣,我在这里再补充一下。这里的测试方法主要是指测试客户端如何发起百万连接并保持它们。由于受到单机单ip的端口数限制,即如下

pomelo@debian:~/socktest$ cat /proc/sys/net/ipv4/ip_local_port_range

2048         65500

  单个客户端ip只能建立6万多连接,所以我们需要大约50个独立ip发起300万的连接。为简单起见,使用50台512M内存的虚拟机作为客户端。问题归结为两个方面:

  1、单客户端如何建立并保持6万连接

  2、如何控制几十个客户端

  我们以java编写客户端代码。首先我们尝试的是一线程一连接的方式。这样在java中就需要维护6万个线程及其相关的对象,包括连接对象。很快我们就发现客户端java进程出现了OOM,512M内存不够用了。我们分析下测试目标,目的是保持6万个连接对象,在这种方式下我们相当于是使用了线程这种容器来保存这些对象,但由于线程本身的内存开销巨大,因此我们应该考虑换个轻量级的瓶子来装这些连接对象。

  最终代码如下,即在一个线程内顺序建立连接,并将连接保存到一个数组中,至此就解决了上文问题中的一个方面

private static int n = 0;
private static Socket[] sockList = null;
static {
    n = Integer.valueOf(Config.getProperty("socket.num"));
    sockList = new Socket[n];
}
public void connect(String host, int port) throws UnknownHostException {
    Socket so = null;
    long sleepTime = Integer.valueOf(Config.getProperty("socket.sleep"));
    for (int i=0;i<n;i++) {
        try {
           so = new Socket(host, port);
           sockList[i] = so;
           Thread.sleep(sleepTime);
       } catch (IOException e) {
           logger.error(e.getMessage());
       } catch (InterruptedException e) {
          
       }
    }
}

  接着,又是如何控制几十台客户端呢?其实比较简单,就是在shell脚本中通过ssh调用部署在客户端机器上的测试程序。主要有两个问题需要注意,一是ssh需要认证,我们可以在任意机器上产生无密码的ssh公私钥对,将公钥分发到客户端机器上。二是设置一个ip列表的配置文件。

  这样,两个问题都解决了,可以开始测试了。测试过程及其问题不完全记录可以点这里。

posted @ 2013-06-05 10:43 顺其自然EVO 阅读(185) | 评论 (0)编辑 收藏

移动设备应用的灰盒测试与评估的三步走

所谓移动设备应用的灰盒测试是指,将传统的源代码检查(白盒测试)与前期测试(黑盒测试)结合起来的一种技术。测试人员必须检查应用程序的代码库,审查关键功能代码,审查常见的错误编码或非法编码方法。此外,测试人员还可以执行黑盒测试来审查应用,并根据所确认的漏洞定位找到代码库中的目标代码。

  为什么要执行移动应用的灰盒测试与评估呢?答案很简单:找到高风险代码;确认漏洞的根本原因。

  灰盒测试应当遵循如下三大步骤:

  一、威胁建模

  威胁建模可以使测试团队首先确认有可能对移动应用产生最大影响的威胁。测试人员在这个阶段的主要目的是区分特定应用组件或代码的优先顺序。测试团队通过理解应用程序架构的文档资料,应当逐渐熟知移动应用的基本架构和使用情况。

  收集信息

  通过与移动应用的开发团队协作,测试团队应当获得有助于帮助其理解移动应用的设计和功能的文档资料。这些文档资料中所描述的细节,可以为威胁建模过程中的所有步骤提供基础。

  执行侦察和应用映射

  理解移动应用如何实现其功能对于创建移动应用模型至关重要。在此阶段,测试团队应当人工检查移动应用的实例。然后,团队应当检查移动应用的匿名部分和认证部分,同时关注处理敏感数据和功能的部分。在此阶段,要提供架构、配置、过程、用户、技术等各方面的证明文件,以利于下一阶段的使用。

  需要重点关注并用于下一阶段针对性测试的方面有:管理界面、敏感信息的传输、外部或第三方应用的接口、移动协议(如SMS、MMS、WAP等)的使用。

  测试团队应当记录在此期间的每一种请求和响应,以便于使用本地代理工具和网络嗅探工具进行日后分析。

  定义系统和可信边界

  在检查的下一阶段,评估团队应当构建一个移动应用及数据流程图中的系列过程的可视化模型。数据流程图要确认系统边界和围绕移动应用的每一个组件的可信边界。确认系统边界可以使测试团队初步明确数据流入或流出系统或其组件(即数据入口和出口点)的所有位置。随后,在代码检查阶段,测试团队应当检验在每一个系统边界是否执行了适当的验证和编码技术。与此类似,确定可信边界可以查明测试团队能够检验代码中的认证和授权部分。

  将威胁映射到功能

  在定义了所有的流程图要素后,测试团队应当将所有要素映射到资产威胁,其目的在于定义移动应用中的“热点”,进而可以构建一个测试计划。在针对性的代码检查阶段,测试团队应当全面测试计划中的每一个项目。

  二、漏洞确认

  在应用程序的评估过程中,应当重点检查前一阶段所确认的热点源码。除了要检查源代码检查不易发现的应用程序漏洞,企业还应当执行黑盒类的评估,用以确认网络或主机层的漏洞。为了补充应用程序组件的人工检查,这个测试阶段应当采用自动化的扫描。

  代码分析和扫描

  自动化扫描工具可以分析全部源代码,从而初步发现安全问题。在此阶段,测试者应当利用商业类工具和私有工具来扫描有安全问题征兆的代码和可导致漏洞的常见编程错误。源代码分析阶段应当设法确认可影响到主机、服务器和网络的漏洞。

  人工分析

  在此阶段,我们建议详细检查应用程序的代码,其目的是为了发现应用程序架构所独有的安全漏洞。在检查代码时,建议将以下几种技术结合使用:

  1、许可分析:许多平台要求移动应用声明在执行期间试图访问哪些功能。然后,设备将对应用程序限制使用这些特定的功能。测试人员可以针对这些功能发动攻击,并尝试绕过这些限制,以检验其效果。

  2、控制流分析:该技术用于分析代码中的逻辑条件。这种方法可以使测试人员确认常见的逻辑漏洞,例如,程序无法处理例外、不适当的授权限制等。

  3、数据流分析:该技术跟踪从输入点到输出点的数据,尤其适用于确认常见的输入验证错误,如SQL注入和跨站脚本利用。

  为应用这些技术,我们建议企业将移动应用分割成不同的功能组件。测试者应当检查每一个组件,以查找常见的不安全的编程方法,这些方法包括:

  1、认证:弱口令要求、用户名穷举、账户停用、cookie重放攻击、后门等。

  2、授权:特权提升、不适当的权力分配、机密数据的暴露、数据受损等。

  3、会话管理:会话陷阱、会话超时、会话劫持、不适当的会话终止、会话重放、中间人攻击等。

  4、配置管理:对管理界面的非授权访问、对配置文件的非授权访问、配置数据的检索、分配给过程和服务账户的过多特权。

  5、输入验证:参数损害、缓冲区域溢出、跨站脚本攻击、SQL注入、XPATH劫持、命令劫持等。

  6、数据保护:对移动应用或用户的私密进行硬编码、网络通信嗅探、错误的密钥生成或密钥管理,弱加密等。

 7、例外处理:信息泄露、拒绝服务等。

  8、审计和日志:日志伪造、操纵日志文件、日志文件破坏等。

  9、缓存:在移动应用的生命周期内,击键、快照、剪贴板内容和文件有可能被缓存到设备的不同存储位置。

  10、发布通知:将数据从服务器传输到应用。

  11、基于位置的服务:试图泄露或欺骗位置数据。

  此外,还有以明文形式将口令存放到数据库中等。

  检查代码中的架构安全问题

  如果应用程序使用了特定的安全机制,或者具备可以减轻某些“臭名昭著”的安全威胁的功能,这一步就相当重要了。最后的代码检查用于验证应用程序架构的特定安全功能:

  加密:由于定制的加密方案一般都没有强健的加密机制,所以企业应当检查方案,以验证其是否可以对敏感数据提供充分的保护。

  协议:测试人员应当检查应用通信的私有协议,用以决定其应对破坏和侦听的能力。

  会话管理:测试者应检查如下两方面,一是创建特定会话标识符的企图,二是会话管理进程。这样做的目的是为了衡量其会话发生管理错误时的保护能力。

  访问限制:测试者要检查特定HTTP头的使用或者其它的特定协议要素,用以控制访问,防止未授权的访问。

  安全代码:有些代码是为解决以前所发现的安全问题而编写的,对此测试者要专门检查,以检验其功效。

  服务器架构:测试者要检查用来支持移动应用的外部Web服务和服务器。

  三、漏洞利用

  在这个阶段,测试者必须制定测试计划,其目的是为了对源代码进行深入分析,查找是否存在常见的不安全编码方法。然后,重点检查移动应用的特定安全机制。测试者还要查找、检查代码中的架构安全问题。

  验证所确认的问题

  测试团队要分析来自漏洞扫描的结果,去掉那些似是而非的信息,并着手构建可利用漏洞的案例。

  利用移动应用的独有功能

  灰盒测试方法的主要好处是能够最大限度地利用漏洞。在此阶段中,测试者要尝试利用在移动应用的实例中表现不明显的认证漏洞和授权漏洞。这些漏洞可能会导致对功能或数据的非法访问,并给企业带来巨大风险。测试者还要利用业务逻辑(用于控制用户如何在移动应用中执行操作)中的缺陷。这些缺陷一般被用于欺诈移动应用的用户或公司。

  将漏洞利用与源代码联系起来

  在测试者证明了可利用的漏洞后,就要将可利用的漏洞与相关的特定代码部分联系起来。这可以使开发人员快速地理解问题,并可以评估进行漏洞修复需要花费的工作量。

  分析风险

  测试者要评估可利用的漏洞,并根据每个漏洞给公司带来的风险,对漏洞进行评级。对于漏洞,测试者还要评估在漏洞被利用后,它可能对公司造成的影响。如果测试者能够利用多个漏洞并带来更大的影响,那么这种分析就具有多重意义。

  提供具体的技术建议

  在评估了每个可利用漏洞的风险后,测试者要给出移动应用架构和代码编写的具体建议,如果可能最好包括源代码。然后,开发者就可以利用这些建议来减轻或修复漏洞,从而减少应用风险。测试者的建议还可以提供安全的编码指南,用以解决或修复移动应用的漏洞。

  在这里提出几条移动安全的建议,供开发者和测试者参考:把移动安全理念纳入到开发项目中;构建并实施一种可以监管移动应用的开发并确保可理解性的策略;培训移动应用的开发人员,帮助其实施安全的编码;测试是否可以限制传输到移动设备的敏感数据;评估针对Web应用和基础架构的威胁。

相关链接:

如何对移动应用进行黑盒测试

posted @ 2013-06-05 10:42 顺其自然EVO 阅读(207) | 评论 (0)编辑 收藏

版本控制之我见——版本控制心得(二)

对于一个采用版本控制进行软件开发的多人开发团队而言,其一般的开发方式是:采用服务器/客户端的形式,在上面分别安装版本控制工具的服务器和客户端版本,软件放在服务器上为大家所共享,开发人员在客户端从服务器上将软件的相关部分下载到本地,进行修改,改动结果最终提交到服务器上。

  1、软件版本控制的主要功能和主要特点

  版本控制的功能:跟踪记录整个软件的开发过程,包括软件本身和相关文档(所带来的结果是:可标识不同阶段的软件及相关文档,进行差别分析;对软件进行可撤消的修改;便于汇总不同人员所做的修改),辅助协调和管理软件开发团队。

  我认为,对于软件的版本控制而言,其主要特点包括如下:

  1.1 空间上集中统一管理

  由于采用服务器/客户端方式,尽管开发人员可以在自己的本地留有备份,但最终唯一有效的只有服务器端的那个原始拷贝。一定程度可以解决一致性问题、冗余问题。

  1.2 时间上全程跟踪记录

  工具将会自动记录每个更改细节,和不同时期的不同版本。一定程度可以解决冗余问题、事务性问题、并发性问题。

  1.3 操作权限控制

  对于不同开发人员,对软件的不同部分可以定义不同的访问权限。一定程度可以解决安全性问题。

  1.4 自动或半自动

  由于有工具辅助控制,可以减轻开发人员的负担,节省时间,同时降低人为错误。像软件整合这样的工作,其工作量可以相对减轻。

  2、软件版本控制评价标准

  我认为,对软件进行版本控制,衡量其效果的标准,归根结底有两点:效率和质量。如果版本控制最终使软件开发效率得到提高、使软件质量得到提升,那就是成功的,反之则是失败的。效率的提高比较容易理解,质量的提升则体现在:软件的一致性、冗余程度等。需要指出的是,单就版本控制工具本身并不能保证这两点。对工具不熟悉或错误的使用,以及开发人员的不良习惯等都将导致失败。有时可能反而降低效率。

  3、几个重要观点

  3.1 版本控制包括代码和文档

  我认为,广义的版本控制也应该包括和代码相关的其他内容,主要指文档。虽然文档的一致性问题并不像代码那么突出,多人同时修改一个文档的情况一般较为少见,但将文档只留一个服务器拷贝,会便于集中管理,减少冗余,加上工具的全程跟踪记录,可以随时查看不同时期文档的内容,相互比对。

  3.2 版本控制管理应该包括工具软件的使用和人为规范的遵循

  在版本控制中,人的因素更为重要,规范的行为可以避免很多意想不到的后果,和错误使用工具所引起的问题。单纯依赖工具,并不能取得良好效果。没有版本控制的意识、对工具的使用不熟悉(一些功能不知道怎么用,一些功能使用错误)、人为的不良习惯,都可能导致错误。因此需要使用版本控制工具的开发人员具有自觉良好的意识和习惯,也需要一些相关的规范和制度的保证。

  3.3 不能忽略版本控制管理员这一角色的重要性

  可以不必单独划定一人来担任这个角色,但如果没有这一角色的存在,任何人都可以任意操作服务器上已纳入版本控制的软件以及版本控制工具的配置信息(比如用户权限信息),或者说任何人都可以做管理员,则又会出现安全性问题。从某种程度上讲,这和没有版本控制下每台机器上都有若干软件版本的情况是等效的。

  3.4 向版本控制过渡是一个循序渐进的、持久的过程

  对于一个团队而言,向版本控制过渡,需要有一个逐步转变的过程。这包括:制订一系列合理的循序渐进的措施,使版本控制的意识逐步得到大家的认可,使人员逐渐养成良好习惯(习惯于这种开发方式)。这是一个持久的过程,需要坚持。

相关链接:

没有使用版本控制的黑暗时代——版本控制心得(一)

posted @ 2013-06-05 10:32 顺其自然EVO 阅读(158) | 评论 (0)编辑 收藏

使用异步方式提高测试脚本运行效率

优化测试脚本中,提高效率是主要目的之一,但是往往效率提升是最难的,因为无从下手。但其实我们平时的测试脚本中有一部分是很容易优化提升效率的,那就是I/O部分。我们常规的做法是在脚本运行前使用JUnit的@Before或者@BeforeClass来进行各种I/O操作,例如读写数据库、读写磁盘文件等,很多时候是为了准备测试数据,这些预置条件花费的时间常常比整个脚本的运行时间都要长,如果能缩短这部分操作的时间,那么效率很得到很大的提升。

  优化的方法很简单,就是将这部分操作异步处理。以数据准备为例,我们最常见的做法是将数据保存在excel中,然后读取excel后再插入数据库,这里就涉及一次磁盘I/O和一次网络I/O,但是准备出来的数据一般并不是在测试脚本的第一步就会被用到,所以可以把预置条件异步执行,与测试脚本并行执行,再需要预置条件处理结果的时候再去获取。

  下面我用一个页面自动化脚本为例来介绍如何提高这部分操作的效率,这段代码用来校验淘宝交易过程中的付款环节,既然是校验付款,那么在预置条件中应该要准备一个未付款状态的订单数据。

  优化前我们的脚本如下:

  Java代码

1.import java.util.concurrent.ExecutionException; 
2.import java.util.concurrent.TimeoutException; 
3. 
4.import org.junit.Before; 
5.import org.junit.Test; 
6. 
7. 
8.public class AsyncSample { 
9.     
10.    private long orderId; 
11.     
12.    @Before 
13.    public void createOrder() { 
14.        //准备订单数据 
15.        orderId = 0L; //赋值准备好的订单号 
16.    } 
17.     
18.    @Test 
19.    public void test() throws InterruptedException, ExecutionException, TimeoutException { 
20.        //步骤一:登录页面 
21.        //步骤二:打开已买到订单页面 
22.        //步骤三:根据订单号定位页面元素位置 
23.        //步骤四:付款 
24.        //断言:验证付款结果 
25.    } 
26. 
27.}

  上面的脚本中,最耗时的应该在@Before的createOrder方法中,下面来优化这个方法。

  Java代码

1.import java.util.concurrent.Callable; 
2.import java.util.concurrent.ExecutionException; 
3.import java.util.concurrent.ExecutorService; 
4.import java.util.concurrent.Executors; 
5.import java.util.concurrent.Future; 
6.import java.util.concurrent.TimeUnit; 
7.import java.util.concurrent.TimeoutException; 
8. 
9.import org.junit.AfterClass; 
10.import org.junit.Before; 
11.import org.junit.Test; 
12. 
13. 
14.public class AsyncSample { 
15.     
16.    private static final ExecutorService single = Executors.newSingleThreadExecutor(); 
17.     
18.    private Future<Long> future; 
19.     
20.    @Before 
21.    public void createOrder() { 
22.        future = single.submit(new Callable<Long>() { 
23. 
24.            @Override 
25.            public Long call() throws Exception { 
26.                long orderId = 0L; 
27.                //准备订单数据 
28.                return orderId; //返回订单ID 
29.            } 
30.        }); 
31.    } 
32.     
33.    @AfterClass 
34.    public static void shutdown() { 
35.        single.shutdownNow(); 
36.    } 
37.     
38.    @Test 
39.    public void test() throws InterruptedException, ExecutionException, TimeoutException { 
40.        //步骤一:登录页面 
41.        //步骤二:打开已买到订单页面 
42.        long orderId = future.get(10, TimeUnit.SECONDS); //步骤三:从异步任务中获取订单号 
43.        //步骤四:根据订单号定位页面元素位置 
44.        //步骤五:付款 
45.        //断言:验证付款结果 
46.    } 
47. 
48.}

  为了清楚的说明方法,并没有写太多的代码,都以注释说明取代。可以看到在步骤三时才需要预置条件中准备的测试数据,但是正常情况下,在登录和打开已买到页面的过程中,订单数据已经准备好了,步骤三可以直接拿到订单号然后继续后面的步骤。

  相比原来的脚本,我们充分利用了登录和打开页面这段时间完成了数据准备的工作,所以整个数据准备的时间完全没有了,脚本效率提升是非常明显的。

  当然,也可以将异步的方法作一些封装使其更简洁和易用。另外,对于异步方法的使用需要把握好度,避免大量使用降低代码的可读性和可维护性。

posted @ 2013-06-05 10:31 顺其自然EVO 阅读(317) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 238 239 240 241 242 243 244 245 246 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜