发布新日志

  • 研发手机基本流程(摘自52RD论坛)

    2007-10-23 09:58:08

    研发手机基本流程

    手机设计公司是根据不同的手机研发平台来设计不同性能的产品!
    手机研发的基本流程是:
    用一个较简单的阐释,一般的手机研发公司是需要最基本有六个部门:IDMDHWSWPMSourcingQA
    1
    ID(Industry Design)工业设计
    包括手机的外观、材质、手感、颜色配搭,主要界面的实现与及色彩等方面的设计。

    例如摩托罗拉翻盖的半透明,诺基亚7610的圆弧形外观,索爱W550的阳光橙等。这些给用户的特别感受和体验都是属于手机工业设计的范畴,一部手机是否能成为畅销的产品,手机的工业设计显得特别重要!

    2
    MD(Mechanical Design)结构设计
    手机的前壳、后壳、手机的摄像镜头位置的选择,固定的方式,电池如何连接,手机的厚薄程度。如果是滑盖手机,如何让手机滑上去,怎样实现自动往上弹,SIM卡怎样插和拔的安排,这些都是手机结构设计的范畴。繁琐的部件需要MD的工作人员对材质以及工艺都非常熟识。

    摩托罗拉V3 13.9mm的厚度掀起了手机市场的热潮,V3手机以超薄为卖点,因为它的手机外壳材质选择十分关键,所以V3的外壳是由技术超前的航空级铝合金材质打造而成。可以这样说,特殊外壳材质的选择成就了V3的成功。
    另外有个别用户反应在使用某些超薄滑盖手机的时候,在接听电话时总能感觉到手机前壳的左右摇动,这就是手机结构设计出了问题,由于手机的壳体太薄,通话时的扬声器振动很容易让手机的机身产生了共振。
    3
    HW(Hardware) 硬件设计
    硬件主要设计电路以及天线,而HW是要和MD保持经常性的沟通。
    MD要求做薄,于是电路也要薄才行得通。同时HW也会要求MD放置天线的区域比较大,和电池的距离也要足够远,HW还会要求ID在天线附近不要放置有金 属配件等等。可想而知一部内置天线的设计手机,其制造成本是会较一部外置天线设计的手机贵上20-25%,其主要因素就是天线的设计,物料的要求与及电路 的设计和制造成本平均都是要求较高一些。

    通常结构设计师(MD)与工业设计师(ID)都会有争论,MDID都是画家,画一些大家做不出 来的东西,而ID会说MD笨,不按他们的设计做,所以手机卖得不好。所以,一款新的手机在动手设计前,各个部门都会对ID部门的设计创意进行评审,一个好 ID一定要是一个可以实现的创意,并且客户的体验感觉要很好才行。当年摩托罗拉V70ID就是一个很好的实现创意例子,后期市场的反应也不错,而西门 子的Xelibri的创意虽然也很好,也可实现,但可惜的是最终客户的使用感觉并不好,所以一个真正好的创意,不但要好看,可实现,而且还要好用。

    另外HW也会与ID吵架,ID喜欢用金属装饰,但是金属会影响了天线的设计以及容易产生静电的问题,因此HW会很恼火,ID/MD会开发新材料,才能应付ID的要求。诺基亚8800就是一个好例子,既有金属感,又不影响天线的接收能力。
    ?
    4
    SW(Software)软件设计
    相对来说,SW是更容易为大家所理解,由于计算机的普及,让我们最大程度地接触了各种各样的软件,手机操作界面的模式,大家经常看到的手机九官格操作菜单的实现,这都是SW设计的范畴。

    SW
    要充分考虑到界面的可操作性,是否人性化,是否美观的因素。SW测试非常复杂,名目繁多,SW的测试不仅只是在寻找Bug,一致性的测试、兼容性的测试 等都是非常重要的项目,在目前内容为主的信息时代,软件才是手机的最终幕后支柱,硬件的驱动是软件来实现,软件和硬件的工程师之间的冲突相信是不会比 其它部门少,这种关系的绕来绕去,所以便需要有PM(Project Management)项目管理来协调了。
    5
    PM(Project Management)项目管理
    规模公司的PM都分得非常细致,比如TPM (Technologly Of Project Management),即专门管技术的PM,而普通的PM,只管理项目的进度各协调工作,PM这个部门通常存在于那些自己设计,自己生产,自己销售手机 的公司,AMAccount Manager)的职位恐怕大家都不陌生,作为客户经理,对公司内部是代表客户提出要求,对外则代表公司的整体形象,在两者之间起着不可或缺的桥梁作用。

    6
    Sourcing资源开发部
    资源开发部的员工要不停地去挖掘新的资源,如新材质、新的手机组件、测试器材等,当手机开始试产时,他们要保证生产线上所需要的所有生产物料齐备。

    手机进行小批量试生产,考察的不仅是软/硬件的成熟度,还包括考察生产工艺和生产的测试技术,有些手机在进行到这个阶段时,却通过不了这一关的话,最后是以失败告终。于是这款新设计的手机便不会出现在市场上了,而投入的开发资金和人力却付之流水,是一个极大的损失。

    7
    QA(Quality Assurance)质量监督
    QA
    部门负担起整个流程质量保证的工作,督促开发过程是否符合预定的流程,保证项目的可生产性,有很多新设计的手机,就因为碰上了不可生产的某种因素而放弃了。

    生产一部手机不是在实验室内做实验那么简单,一旦生产就是成千上万部,要保证每一部产品的优质绝非一件简单容易的事。生产一部手机的样品和生产10万部手机完全是两码子事。
    举例:中国的菜馆出的都是样品,麦当劳做的是产品,所以麦当劳可以做得很大,而且到目前为止,中国的菜馆暂时还没有做到像麦当劳的规模是事实,所以手机设计公司才会建立起很多流程来防止出现设计研制出来的手机却不能投入生产的情况。
    不仅如此,一款手机的成功上市,能够卖个满堂红,仍然是需要与大众手机用户有亲密的接触,并且经过用户的反馈以及快速的改善才能成功。
    二、鲜为人知的手机测试项目
    1
    、压力测试
    用自动测试软件连续对手机拨打1000个电话,检查手机是否会发生故障。倘若出了问题,有关的软件就需要重新编写了。所以有时候手机上会出现不同的软件版本存在的情况,其实告诉大家一个秘密,手机的版本越多,这可以证明该手机在推出发售前,未经过充分的测试工作便发售了。

    2
    、抗摔性测试
    抗摔性测试是由专门的Pprt可靠性实验室来进行,0.5m的微跌落测试要做300/(手机有六个面)。而2m的跌落测试每个面需各做一次,还仿真人把手机抛到桌面,而手机所用的电池,也要经过最少4m的高度,单独的向着地面撞击跌落100次而不能有破裂的情况出现。

    3
    、高/低温测试
    让手机处于不同温度环境下测试手机的适应性,低温一般在零下20摄氏度,高温则在80摄氏度左右。

    4
    、高湿度测试
    用一个专门的柜子来作滴水测试,仿真人出汗的情况(水内渗入一定比例的盐分),约需进行30个小时。

    5
    、百格测试(又称界豆腐测试)
    H4硬度的铅笔在手机外壳上画100格子,看看手机的外壳是否会掉下油漆,有些要求更严格的手机,会在手机的外壳上再涂抹上一些名牌的化妆品,看看是否因有不同的化学成分而将手机的油漆产生异味或者掉漆的可能。


    6
    、翻盖可靠性测试
    对翻盖手机进行翻盖10万次,检查手机壳体的损耗情况,是用一部翻盖的仿真机来进行,它可以设置翻盖的力度、角度等。
    7
    、扭矩测试
    直机用夹具夹住两头,一个往左拧,一个往右拧。扭矩测试主要是考验手机壳体和手机内面大型器件的强度。

    8
    、静电测试
    北方地区,天气较为干燥,手摸金属的东西容易产生静电,会引致击穿手机的电路,有些设计不好的手机就是这么样突然损坏了。进行这种测试的工具,是一个被称 静电枪的铜板,静电枪会调较到10-15KV的高压低电流的状况,对手机的所有金属接触点进行放电的击试,时间约为300ms-2s左右,并在一间 有湿度控制的房间内进行,而有关的充电器(火牛)也会有同样的测试,合格才能出厂发售。


    9
    、按键寿命测试
    借助机器以给设定的力量对键盘击打10万次,假使用户每按键100次,就是1000天,相当于用户使用手机三年左右的时间。

    10
    、沙尘测试
    将手机放入特定的箱子内,细小的沙子被吹风机鼓吹起来,经过约三小时后,打开手机并察看手机内部是否有沙子进入。如果有,那么手机的密闭性设计不够好,其结构设计有待重新调整。
    此外,手机的测试还包含了更多更离奇的测项目,比如把手机放在铁板上打电话加以测试,由于此时磁场发生了变化,什么情况都会发生,例如寻找不到SIM卡等。

    用铁丝在手机底部连接器内拨来拨去,主要是要考虑到手袋内有锁匙的情况下,是否会令手机出现短路的问题。
    还有故意把充电器/电池反接测试,看看手机的保护电路设计是否能正常运作,靠近日光灯打电话的测试,人体吸收电磁波比例的测试,以及靠近心脏起博器打电话的测试等等,上述所提及的各种测试都是不可少的。

  • 黑盒测试&白盒测试 (有待补充完整)

    2007-10-23 09:50:53

    1, 黑盒测试:也称功能测试或数据驱动测试。它在已知产品应具有的功能的条件下,通过测试来检测每个功能是否都能正常使用

    黑盒测试-主要试图发现几类错误:功能不对或遗漏、界面错误、数据结构或外部数据库访问错误、性能错误、初始化和终止错误。

    黑盒测试有两种基本方法,即通过测试和失败测试

    具体的黑盒测试方法包括等价类划分、因果图、正交实验设计法、边值分析、判定表驱动法、功能测试等。

     

     

    功能测试:检查软件的功能是否符合规格说明

    基本方法: 测试基本的方法是构造一些合理输入(在定义域内),检查是否得到期望的输出。

    (在定义域内使用等价类划分比较有效)

     

    等价类划分;是把程序的输入域划分成若干部分,然后从每个部分中选取少数代表性数据作为测试用例。每一类的代表性数据在测试中的作用等价于这一类中的其他值。

    容错性测试:检查软件在异常条件下的行为(输入不同的数据类型或者定义域之外的值进行测试)。

     

     

    边界值分析(Boundary Value AnalysisBVA:是一种补充等价划分的测试用例设计技术,它不是选择等价类的任意元素,而是选择等价类边界的测试用例。实践证明,在设计测试用例时,对边界附近的处理必须给予足够的重视,为检验边界附近的处理专门设计测试用例,常常可以取得良好的测试效果。BVA不仅重视输人条件边界,而且也从输出域导出测试用例。

    边界值设计测试遵循的五条原则:
    1
    、如果输入条件规定了取值范围,应以该范围的边界内及刚刚超范围边界外的值作为测试用例。如以ab为边界,测试用例应当包含ab及略大于a和略小于b的值;

    2
    、若规定了值的个数,分别以最大、最小个数及稍小于最小、稍大于最大个数作为测试用例;

    3
    、针对每个输出条件使用上述12条原则;

    4
    、如果程序规格说明中提到的输入或输出域是个有序的集合(如顺序文件、表格等),就应注意选取有序集的第一个和最后一个元素作为测试用例;

    5
    、分析规格说明,找出其他的可能边界条件。

     

     

    错误推测设计方法:就是基于经验和直觉推测程序中所有可能存在的各种错误,从而有针对性地设计测试用例的方法。

     

    因果图方法:是从用自然语言书写的程序规格说明的描述中找出因(输入条件)和果(输出或程序状态的改变),可以通过因果图转换为判定表。

     

    正交试验设计法,\:就是使用已经造好了的正交表格来安排试验并进行数据分析的一种方法,目的是用最少的测试用例达到最高的测试覆盖率。

     

     

    2, 白盒测试
    白盒测试也称结构测试或逻辑驱动测试,它是按照程序内部的结构测试程序,通过测试来检测产品内部动作是否按照设计规格说明书的规定正常进行,检验程序中的每条通路是否都能按预定要求正确工作

  • 自动化测试的7个步骤(转)

    2007-10-23 09:49:41

    【摘要】 我们对自动化测试充满了希望,然而,自动化测试却经常带给我们沮丧和失望。虽然,自动化测试可以把我们从困难的环境中解放出来,在实施自动化测试解决问题的同时,又带来同样多的问题。在开展自动化测试的工作中,关键问题是遵循软件开发的基本规则。本文介绍自动化测试的 7 个步骤:改进自动化测试过程,定义需求,验证概念,支持产品的可测试性,具有可延续性的设计( design for sustainability ),有计划的部署和面对成功的挑战。按照以上 7 个步骤,安排你的人员、工具和制定你的自动化测试项目计划,你将会通往一条成功之路。

      一个故事 :

      我在很多软件公司工作过,公司规模有大有小,也和来自其他公司的人员交流,因此经历过或者听说过影响自动化测试效果的各种各样的的问题。本文将提供若干方法规避可能在自动化测试中出现的问题。我先给大家讲一个故事,以便各位了解自动化测试会出现哪些问题。

      以前,我们有一个软件项目,开发小组内所有的人都认为应该在项目中采用自动化测试。软件项目的经理是 Anita Delegate 。她评估了所有可能采用的自动化测试工具,最后选择了一种,并且购买了几份拷贝。她委派一位员工 ——Jerry Overworked 负责自动化测试工作。 Jerry 除了负责自动化测试工作,还有其他的很多任务。他尝试使用刚刚购买的自动化测试工具。当把测试工具应用到软件产品测试中的时候,遇到了问题。这个测试工具太复杂,难于配置。他不得不给测试工具的客户支持热线打了几个电话。最后, Jerry 认识到,他需要测试工具的技术支持人员到现场帮助安装测试工具,并找出其中的问题。在打过几个电话后,测试工具厂商派过来一位技术专家。技术专家到达后,找出问题所在,测试工具可以正常工作了。这还算是顺利了。但是,几个月后,他们还是没有真正实现测试自动化, Jerry 拒绝继续从事这个项目的工作,他害怕自动化测试会一事无成,只是浪费时间而已。

      项目经理 Anita 把项目重新指派给 Kevin Shorttimer ,一位刚刚被雇佣来做软件测试的人员。 Kevin 刚刚获得计算机科学的学位,希望通过这份工作迈向更有挑战性的、值得去做的工作。 Anita 送 Kevin 参加工具培训,避免 Kevin 步 Jerry 的后尘 —— 由于使用测试工具遇到困难而变得沮丧,导致放弃负责的项目。 Kevin 非常兴奋。这个项目的测试需要重复测试,有点令人讨厌,因此,他非常愿意采用自动化测试。一个主要的版本发布后, Kevin 准备开始全天的自动化测试,他非常渴望得到一个机会证明自己可以写非常复杂的,有难度的代码。他建立了一个测试库,使用了一些技巧的方法,可以支持大部分的测试,这比原计划多花费了很多时间,不过, Kevin 使整个测试工作开展的很顺利。他用已有的测试套测试新的产品版本,并且确实发现了 bug 。接下来, Kevin 得到一个从事软件开发职位的机会,离开了自动化的岗位。

      Ahmed Hardluck 接手 Kevin 的工作,从事自动化测试执行工作。他发现 Kevin 留下的文档不仅少,并且没有太多的价值。 Ahmed 花费不少时间去弄清楚已有的测试设计和研究如何开展测试执行工作。这个过程中, Ahmed 经历了很多失败,并且不能确信测试执行的方法是否正确。测试执行中,执行失败后的错误的提示信息也没有太多的参考价值,他不得不更深的钻研。一些测试执行看起来仿佛永远没有结束。另外一些测试执行需要一些特定的测试环境搭建要求,他更新测试环境搭建文档,坚持不懈地工作。后来,在自动化测试执行中,它发现几个执行失败的结果,经过分析,是回归测试的软件版本中有 BUG ,导致测试执行失败,发现产品的 BUG 后,每个人都很高兴。接下来,他仔细分析测试套中的内容,希望通过优化测试套使测试变得更可靠,但是,这个工作一直没有完成,预期的优化结果也没有达到。按照计划,产品的下一个发布版本有几个主要的改动, Ahmed 立刻意识到产品的改动会破坏已有的自动化测试设计。接下来,在测试产品的新版本中,绝大多数测试用例执行失败了, Ahmed 对执行失败的测试研究了很长时间,然后,从其他人那里寻求帮助。经过商讨,自动化测试应该根据产品的新接口做修改,自动化测试才能运转起来。最后,大家根据新接口修改自动化测试,测试都通过了。产品发布到了市场上。接下来,用户立刻打来投诉电话,投诉软件无法工作。大家才发现自己改写了一些自动化测试脚本,导致一些错误提示信息被忽略了。虽然,实际上测试执行是失败的,但是,由于改写脚本时的一个编程错误导致失败的测试执行结果被忽略了。这个产品终于失败了。

      这是我的故事。或许您曾经亲身经历了故事当中某些情节。不过,我希望你没有这样的相似结局。本文将给出一些建议,避免出现这样的结局。

      问题

      这个故事阐明了几个使自动化测试项目陷入困境的原因:

      自动化测试时间不充足:根据项目计划的安排,测试人员往往被安排利用自己的个人时间或者项目后期介入自动化测试。这使得自动化测试无法得到充分的时间,无法得到真正的关注。

      缺乏清晰的目标:有很多好的理由去开展自动化测试工作,诸如自动化测试可以节省时间,使测试更加简单,提高测试的覆盖率,可以让测试人员保持更好的测试主动性。但是,自动化测试不可能同时满足上述的目标。不同的人员对自动化测试有不同的希望,这些希望应该提出来,否则很可能面对的是失望。

      缺乏经验:尝试测试自己的程序的初级的程序员经常采用自动化自动化测试。由于缺乏经验,很难保证自动化测试的顺利开展。

      更新换代频繁( High turnover ):测试自动化往往需要花费很多时间学习的,当自动化测试更新换代频繁的时候,你就丧失了刚刚学习到的自动化测试经验。

      对于绝望的反应:在测试还远没有开始的时候,问题就已经潜伏在软件中了。软件测试不过是发现了这些潜伏的问题而已。就测试本身而言,测试是一件很困难的工作。当在修改过的软件上一遍接一遍的测试时,测试人员变得疲劳起来。测试什么时候后结束?当按照计划的安排,软件应该交付的时候,测试人员的绝望变得尤其强烈。如果不需要测试,那该有多好呀!在这种环境中,自动化测试可能是个可以选择的解决方法。但是,自动化测试却未必是最好的选择,他不是一个现实的解决方法,更像是一个希望。

      不愿思考软件测试:很多人发现实现产品的自动化测试比测试本身更有趣。在很多软件项目发生这样的情况,自动化工程师不参与到软件测试的具体活动中。由于测试的自动化与测试的人为割裂,导致很多自动化对软件测试并没有太大的帮助。

      关注于技术:如何实现软件的自动化测试是一个很吸引人的技术问题。不过,过多的关注如何实现自动化测试,导致忽略了自动化测试方案是否符合测试需要。

      遵守软件开发的规则

      你可能了解 SEI (软件工程研究所)提出的 CMM (能力成熟度模型)。 CMM 分为 5 个界别,该模型用来对软件开发组织划分等级。 Jerry Weinberg (美国著名软件工程专家)也创建了自己的一套软件组织模型,在他的组织模型中增加了一个额外的级别,他称之为零级别。很显然,一个零模式的组织实际上也是开发软件;零模式组织中,在开发人员和用户之间没有差别 [Weinberg 1992] 。恰恰在这类组织环境中,经常采用自动化测试方法。因此,把资源用于自动化测试,并且把自动化测试当作一个软件开发活动对待,把软件测试自动化提升到一级。这是解决测试自动化的核心的方案。我们应该像运作其他的开发项目一样来运作软件自动化测试项目。

      像其他软件开发项目一样,我们需要软件开发人员专注于测试自动化的开发任务;像其他软件开发项目一样,自动化测试可以自动完成具体的测试任务,对于具体的测试任务来说,自动化开发人员可能不是这方面的专家,因此,软件测试专家应该提供具体测试任务相关的咨询,并且提供测试自动化的需求;像其他软件开发项目一样,如果在开发编码之前,对测试自动化作了整体设计有助于测试自动化开发的顺利开展。像其他软件开发项目一样,自动化测试代码需要跟踪和维护,因此,需要采用源代码管理。像其他软件开发项目一样,测试自动化也会出现 BUG ,因此,需要有计划的跟踪 BUG ,并且对修改后的 BUG 进行测试。像其他软件开发项目一样,用户需要知道如何使用软件,因此,需要提供用户使用手册。

      本文中不对软件开发做过多讲述。我假定您属于某个软件组织,该组织已经知道采用何种合理的、有效的方法开发软件。我仅仅是推动您在自动化测试开发过程中遵守已经建立的软件开发规则而已。本文按照在软件开发项目中采用的标准步骤组织的,重点关注测试自动化相关的事宜和挑战。

      ? 改进软件测试过程

      ? 定义需求

      ? 验证概念

      ? 支持产品的可测试性

      ? 可延续性的设计( design for sustainability )

      ? 有计划的部署

      ? 面对成功的挑战

      步骤一:改进软件测试过程

      如果你负责提高一个商业交易操作的效率,首先,你应该确认已经很好的定义了这个操作的具体过程。然后,在你投入时间和金钱采用计算机提供一套自动化的商业交易操作系统之前,你想知道是否可以采用更简单、成本更低的的方法。同样的,上述过程也是用于自动化测试。我更愿意把 “ 测试自动化 ” 这个词解释成能够使测试过程简单并有效率,使测试过程更为快捷,没有延误。运行在计算机上的自动化测试脚本只是自动化测试的一个方面而已。

      例如,很多测试小组都是在回归测试环节开始采用测试自动化的方法。回归测试需要频繁的执行,再执行,去检查曾经执行过的有效的测试用例没有因为软件的变动而执行失败。回归测试需要反复执行,并且单调乏味。怎样才能做好回归测试文档化的工作呢?通常的做法是采用列有产品特性的列表,然后对照列表检查。这是个很好的开始,回归测试检查列表可以告诉你应该测试哪些方面。不过,回归测试检查列表只是合于那些了解产品,并且知道需要采用哪种测试方法的人。

      在你开始测试自动化之前,你需要完善上面提到的回归测试检查表,并且,确保你已经采用了确定的的测试方法,指明测试中需要什么样的数据,并给出设计数据的完整方法。如果测试掌握了基本的产品知识,这会更好。确认可以提供上面提到的文档后,需要明确测试设计的细节描述,还应该描述测试的预期结果,这些通常被忽略,建议测试人员知道。太多的测试人员没有意识到他们缺少什么,并且由于害怕尴尬而不敢去求助。这样一份详细的文档给测试小组带来立竿见影的效果,因为,现在任何一个具有基本产品知识的人根据文档可以开展测试执行工作了。在开始更为完全意义上的测试自动化之前,必须已经完成了测试设计文档。测试设计是测试自动化最主要的测试需求说明。不过,这时候千万不要走极端去过分细致地说明测试执行的每一个步骤,只要确保那些有软件基本操作常识的人员可以根据文档完成测试执行工作既可。但是,不要假定他们理解那些存留在你头脑中的软件测试执行的想法,把这些测试设计的思路描述清楚就可以了。

      我以前负责过一个软件模块的自动化测试工作。这个模块的一些特性导致实现自动化非常困难。当我了解到这项工作无需在很短的时间内完成后,决定制定一个详细回归测试设计方案。我仔细地检查了缺陷跟踪库中与该模块相关的每个已经关闭的缺陷,针对每个缺陷,我写了一个能够发现该问题的测试执行操作。我计划采用这种方法提供一个详细的自动化需求列表,这可以告诉我模块的那一部分最适合自动化测试。在完成上述工作后,我没有机会完成测试自动化的实现工作。不过,当我们需要对这个模块做完整回归测试的时候,我将上面提到的文档提供给若干只了解被测试产品但是没有测试经验的测试人员。依照文档的指导,几乎不需要任何指导的情况下,各自完成了回归测试,并且发现了 BUG 。从某种角度看,这实际上是一次很成功的自动化测试。在这个项目中,我们与其开发自动化测试脚本,还不如把测试执行步骤文档化。后来,在其它项目中,我们开发了自动化测试脚本,发现相关人员只有接受相关培训才能理解并执行自动化测试脚本,如果测试自动化设计的很好,可能会好一些。不过,经过实践我们总结出完成一份设计的比较好的测试文档,比完成一份设计良好的测试脚本简单的多。

      另外一个提高测试效率的简单方法是采用更多的计算机。很多测试人员动辄动用几台计算机,这一点显而易见。我之所以强调采用更多的计算机是因为,我曾经看到一些测试人员被误导在单机上努力的完成某些大容量的自动化测试执行工作,这种情况下由于错误的使用了测试设备、测试环境,导致测试没有效果。因此,自动化测试需要集中考虑所需要的支撑设备。

      针对改进软件测试过程,我的最后一个建议是改进被测试的产品,使它更容易被测试,有很多改进措施既可以帮助用户更好的使用产品,也可以帮助测试人员更好的测试产品。稍后,我将讨论自动化测试的可测试需求。这里,我只是建议给出产品的改进点,这样对手工测试大有帮助。

      一些产品非常难安装,测试人员在安装和卸载软件上花费大量的时间。这种情况下,与其实现产品安装的自动化测试,还不如改进产品的安装功能。采用这种解决办法,最终的用户会受益的。另外的一个处理方法是考虑开发一套自动安装程序,该程序可以和产品一同发布。事实上,现在有很多专门制作安装程序的商用工具。

      另一些产品改进需要利用工具在测试执行的日志中查找错误。采用人工方法,在日志中一页一页的查询报错信息很容易会让人感到乏味。那么,赶快采用自动化方法吧。如果你了解日志中记录的错误信息格式,写出一个错误扫描程序是很容易的事情。如果,你不能确定日志中的错误信息格式,就开始动手写错误扫描程序,很可能面临的是一场灾难。不要忘记本文开篇讲的那个故事中提到的测试套无法判断测试用例是否执行失败的例子。最终用户也不愿意采用通过搜索日志的方法查找错误信息。修改错误信息的格式,使其适合日志扫描程序,便于扫描工具能够准确的扫描到所有的错误信息。这样,在测试中就可以使用扫描工具了。

      通过改进产品的性能对测试也是大有帮助的。很显然的,如果产品的性能影响了测试速度,鉴别出性能比较差的产品功能,并度量该产品功能的性能,把它作为影响测试进度的缺陷,提交缺陷报告。

      上面所述的几个方面可以在无需构建自动化测试系统的情况下,大幅度的提高测试效率。改进软件测试过程会花费你构建自动化测试系统的时间,不过改进测试过程无疑可以使你的自动化测试项目更为顺利开展起来。

      步骤二:定义需求

      在前面的故事中,自动化工程师和自动化测试的发起者的目标存在偏差。为了避免这种情况,需要在自动化测试需求上保持一致。应该有一份自动化测试需求,用来描述需要测试什么。测试需求应该在测试设计阶段详细描述出来,自动化测试需求描述了自动化测试的目标。很多人认为自动化测试显然是一件好事情,但是,他们不愿意对自动化测试的目标给出清晰的描述。下面是人们选用自动化测试的几个原因:

      ? 加快测试进度从而加快产品发布进度

      ? 更多的测试

      ? 通过减少手工测试降低测试成本

      ? 提高测试覆盖率

      ? 保证一致性

      ? 提高测试的可靠性

      ? 测试工作可以由技术能力不强测试人员完成

      ? 定义测试过程,避免过分依赖个人

      ? 测试变得更加有趣

      ? 提高了编程技能

      开发管理、测试管理和测试人员实现自动化测试的目标常常是有差别的。除非三者之间达成一致,否则很难定义什么是成功的自动化测试。

      当然,不同的情况下,有的自动化测试目标比较容易达到,有的则比较难以达到。测试自动化往往对测试人员的技术水平要求很高,测试人员必须能理解充分的理解自动化测试,从而通过自动化测试不断发现软件的缺陷。不过,自动化测试不利于测试人员不断的积累测试经验。不管怎么样,在开始自动化测试之前应该确定自动化测试成功的标准。

      手工测试人员在测试执行过程中的一些操作能够发现不引人注意的问题。他们计划并获取必要的测试资源,建立测试环境,执行测试用例。测试过程中,如果有什么异常的情况发生,手工测试人员立刻可以关注到。他们对比实际测试结果和预期测试结果,记录测试结果,复位被测试的软件系统,准备下一个软件测试用例的环境。他们分析各种测试用例执行失败的情况,研究测试过程可疑的现象,寻找测试用例执行失败的过程,设计并执行其他的测试用例帮助定位软件缺陷。接下来,他们写作缺陷报告单,保证缺陷被修改,并且总结所有的缺陷报告单,以便其他人能够了解测试的执行情况。

      千万不要强行在测试的每个部分都采用自动化方式。寻找能够带来最大回报的部分,部分的采用自动化测试是最好的方法。或许你可能发现采用自动化执行和手动确认测试执行结果的方式是个很好的选择,或许你可以采用自动化确认测试结果和手工测试执行相结合和方式。我听到有人讲,除非测试的各个环节都采用自动化方式,否则不是真正意义上的自动化测试,这真是胡言乱语。如果仅仅是为了寻找挑战,可以尝试在测试的每个环节都采用自动化方法。但是,如果寻找成功测试的方法,请关注那些可以快速建立的,可以反复利用的自动化测试。

      定义自动化测试项目的需求要求我们全面地、清楚地考虑各种情况,然后给出权衡后的需求,并且可以使测试相关人员更加合理的提出自己对自动化测试的期望。通过定义自动化测试需求,距离成功的自动化测试近了一步。

      步骤三:验证概念

      在前面的故事当中,那个自动化测试人员在对测试方向一片茫然的情况下一头扎进了自动化测试项目中。不过,在项目的进行中,他得到了来自各个方面的支持。

      你可能还没有认识到这一点,不过,你必须验证自动化测试项目的可行性。验证过程花费的时间往往比人们预期的要长,并且需要来自你身边的各种人的帮助。

      很多年前,我从事一个测试自动化项目的工作,参加项目的人员有各种各样的好点子。我们设计了一个复杂的自动化测试系统,并且非常努力工作去实现系统的每个模块。我们定期的介绍测试自动化的设计思路和工作进度,甚至演示已经完成的部分功能。但是,我们没有演示如何利用该套测试自动化系统如何开展实际的测试工作。最后,整个项目被取消了,此后,我再也没有犯这个错误。

      你需要尽可能快地验证你采用的测试工具和测试方法的可行性,站在产品的角度验证你所测试的产品采用自动化测试的可行性。这通常是很困难的,需要尽快地找出可行性问题的答案,需要确定你的测试工具和测试方法对于被测试的产品和测试人员是否合适。你需要做是验证概念 —— 一个快速、有说服力的测试套可以证明你选在测试工具和测试方法的正确性,从而验证了你的测试概念。你选择的用来验证概念的测试套是评估测试工具的最好的方式。

      对于很多人来说,自动化测试意味着 GUI 自动化测试,我不同意这种观点。我曾经做过 GUI 和非 GUI 自动化测试,并惊奇的发现这两类测试的测试计划有很大的互补性。不过, GUI 测试工具很昂贵、并且过分讲究。选择合适的 GUI 测试工具是很重要的,因为,如果没有选择合适的测试工具,你会遇到很多不可预测的困难。 Elisabeth Hendrickson 曾经写过一篇关于选择测试的工具的指导性文章 [Hendrickson 1999] 。我建议在评估测试工具中,找出能够验证你的想法的证据是很重要的环节。这需要测试工具至少有一个月试用期,你可能打算现在购买一份测试工具,然后直到评估完成后再购买更多份。你需要在付出大笔金钱购买测试工具的之前,找出工具存在的问题。这样,你可以从测试工具供应商得到更好的帮助,当你打算更换工具的时候,你不会感觉很为难。

      下面是一些候选的验证概念的试验:

      回归测试:你准备在每个版本运行同样的测试用例吗?回归测试是最宜采用自动化测试的环节。

      配置测试:你的软件支持多少种不同的平台?你打算在所有支持的平台上测试执行所有的测试用例吗?如果是的,那么采用自动化测试是有帮助的。

      测试环境建立:对于大量不同的测试用例,可能需要相同的测试环境搭建过程。在开展自动化测试执行之前,先把测试环境搭建实现自动化。

      非 GUI 测试:实现命令行和 API 的测试自动化比 GUI 自动化测试容易的多。

      无论采用什么测试方法,定义一个看得见的目标,然后集中在这个目标上。验证你自动化测试概念可以使自动化更进一步迈向成功之路。

      步骤四:支持产品的可测试性

      软件产品一般会用到下面三种不同类别的接口:命令行接口( command line interfaces ,缩写 CLIs) 、应用程序接口( API )、图形用户接口( GUI )。有些产品会用到所有三类接口,有些产品只用到一类或者两类接口,这些是测试中所需要的接口。从本质上看, API 接口和命令行接口比 GUI 接口容易实现自动化,去找一找你的被测产品是否包括 API 接口或者命令行接口。有些时候,这两类接口隐藏在产品的内部,如果确实没有,需要鼓励开发人员在产品中提供命令行接口或者 API 接口,从而支持产品的可测试性。

      下面,更多多的讲解 GUI 自动化测试相关内容。这里有几个原因导致 GUI 自动化测试比预期的要困难。第一个原因是需要手工完成部分脚本。绝大多数自动化测试工具都有 “ 录制回放 ” 或者 “ 捕捉回放 ” 功能,这确实是个很好的方法。可以手工执行测试用例,测试工具在后台记住你的所有操作,然后产生可以用来重复执行的测试用例脚本。这是一个很好的方法,但是很多时候却不能奏效。很多软件测试文章的作者得出结论 “ 录制回放 ” 虽然可以生成部分测试脚本,但是有很多问题导致 “ 录制回放 ” 不能应用到整个测试执行过程中。 [Bach 1996, Pettichord 1996, Kaner 1997, Linz 1998, Hendrickson 1999, Kit 1999, Thomson 1999, Groder 1999]. 结果, GUI 测试还是主要由手工完成。

      第二个原因,把 GUI 自动化测试工和被测试的产品有机的结合在一起需要面临技术上的挑战。经常要在采用众多专家意见和最新的 GUI 接口技术才能使 GUI 测试工具正常工作。这个主要的困难也是 GUI 自动化测试工具价格昂贵的主要原因之一。非标准的、定制的控件会增加测试的困难,解决方法总是有的,可以采用修改产品源代码的方式,也可以从测试工具供应商处升级测试工具。另外,还需要分析测试工具中的 BUG ,并且给工具打补丁。也可能测试工具需要做相当的定制,以便能有效地测试产品界面上的定制控件。 GUI 测试中,困难总是意外出现,让人惊奇。你也可能需要重新设计你的测试以规避那些存在问题的界面控件。

      第三个原因, GUI 设计方案的变动会直接带来 GUI 自动化测试复杂度的提高。在开发的整个过程中,图形界面经常被修改或者完全重设计,这是出了名的事情。一般来讲,第一个版本的图形界面都是很糟糕。如果处在图形界面方案不停变动的时候,就开展 GUI 自动化测试是不会有任何进展的,你只能花费大量的时间修改测试脚本,以适应图形界面的变更。不管怎样,即便界面的修改会导致测试修改脚本,你也不应该反对开发人员改进图形界面。一旦原始的设计完成后,图形界面接口下面的编程接口就固定下来了。

      上面提到的这些原因都是基于采用 GUI 自动化测试的方法完成产品的功能测试。图形界面接口当然需要测试,可以考虑实现 GUI 测试自动化。不过,你也应该考虑采用其他方法测试产品的核心功能,并且这些测试不会因为图形界面发生变化而被中断,这类测试应该采用命令行接口或者 API 接口。我曾经看到有人选择 GUI 自动化测试,因为,他们不打算修改被测试产品,但是,最终他们认识到必须对产品做修改,以保证 GUI 测试自动化可以正常工作。无论你选择哪种方法,自动化都需要对被测试的产品做修改。因此,采用可编程的接口是最可靠的。

      为了让 API 接口测试更为容易,应该把接口与某种解释程序,例如 Tcl 、 Perl 或者 Python 绑定在一起。这使交互式测试成为可能,并且可以缩短自动化测试的开发周期。采用 API 接口的方式,还可以实现独立的产品模块的单元测试自动化。

      一个关于隐藏可编程接口的例子是关于 InstallShield—— 非常流行的制作安装盘的工具。 InstallShield 有命令行选项,采用这种选项可以实现非 GUI 方式的安装盘,采用这种方式,从提前创建好的文件中读取安装选项。这种方式可能比采用 GUI 的安装方式更简单更可靠。

      另一个例子是关于如何避免基于 WEB 软件的 GUI 自动化测试。采用 GUI 测试工具可以通过浏览器操作 WEB 界面。 WEB 浏览器是通过 HTTP 协议与 WEB 服务器交互的,所以直接测试 HTTP 协议更为简单。 Perl 可以直接连接 TCP/IP 端口,完成这类的自动化测试。采用高级接口技术,譬如客户端 JAVA 或者 ActiveX 不可能利用这种方法。但是,如果在合适的环境中采用这种方式,你将发现这种方式的自动化测试比 GUI 自动化测试更加便宜更加简单。

      我曾经受雇在一家公司负责某个产品 GUI 相关的自动化测试,该产品也提供命令行接口,不过,他们已经实现了 GUI 的自动化测试。经过一段时间的研究,我发现找到图形界面中的 BUG 并不困难,不过,用户并不关注图形界面,他们更喜欢使用命令行。我还发现我们还没有针对最新的产品功能(这些功能即可通过 GUI 的方式,也可以通过命令行的方式使用)实现自动化测试。我决定推迟 GUI 自动化测试,扩展命令行测试套,测试新增的产品功能。现在回过头看这个决定,我没有选择 GUI 自动化测试是最大的成功之处,如果采用了 GUI 自动化测试所有的时间和努力都会浪费在其中。他们已经准备好做 GUI 自动化测试了,并且已经购买了一套测试工具和其他需要的东西,但我知道在开展具体的 GUI 自动化测试活动中,会遇到各种各样的困难和障碍。

      无论你需要支持图形界面接口、命令行接口还是 API 接口,如果你尽可能早的在产品设计阶段提出产品的可测试性设计需求,未来的测试工作中,你很可能成功。尽可能早的启动自动化测试项目,提出可测试性需求,会使您走向自动化测试成功之路。

      步骤五:具有可延续性的设计

      在开篇的故事中,我们看到由于自动化工程师把注意力仅仅集中在如何使自动化运转起来,导致测试自动化达不到预期的效果。自动化测试是一个长期的过程,为了与产品新版本的功能和其他相关修改保持一致,自动化测试需要不停的维护和扩充。自动化测试设计中考虑自动化在未来的可扩充性是很关键的,不过,自动化测试的完整性也是很重要的。如果自动化测试程序报告测试用例执行通过,测试人员应该相信得到的结果,测试执行的实际结果也应该是通过了。其实,有很多存在问题的测试用例表面上执行通过了,实际上却执行失败了,并且没有记录任何错误日志,这就是失败的自动化。这种失败的自动化会给整个项目带来灾难性的后果,而当测试人员构建的测试自动化采用了很糟糕的设计方案或者由于后来的修改引入了错误,都会导致这种失败的测试自动化。失败的自动化通常是由于没有关注自动化测试的性能或者没有充分的自动化设计导致的。

      性能: 提高代码的性能往往增加了代码的复杂性,因此,会威胁到代码的可靠性。很少有人关心如何对自动化本身加以测试。通过我对测试套性能的分析,很多测试套都是花费大量的时间等候产品的运行。因此,在不提高产品运行性能的前提下,无法更有效的提高自动化测试执行效率。我怀疑测试自动化工程师只是从计算机课程了解到应该关注软件的性能,而并没有实际的操作经验。如果测试套的性能问题无法改变,那么应该考虑提高硬件的性能;测试套中经常会出现冗余,也可以考虑取出测试套中的冗余或者减少一个测试套中完成的测试任务,都是很好的办法。

      便于分析: 测试自动化执行失败后应该分析失败的结果,这是一个棘手的问题。分析执行失败的自动化测试结果是件困难的事情,需要从多方面着手,测试上报的告警信息是真的还是假的?是不是因为测试套中存在缺陷导致测试执行失败?是不是在搭建测试环境中出现了错误导致测试执行失败?是不是产品中确实存在缺陷导致测试执行失败?有几个方法可以帮助测试执行失败的结果分析,某些方法可以找到问题所在。通过在测试执行之前检查常见的测试环境搭建问题,从而提高测试套的可靠性;通过改进错误输出报告,从而提高测试自动化的错误输出的可分析性;此外,还可以改进自动化测试框架中存在的问题。训练测试人员如何分析测试执行失败结果。甚至可以找到那些不可靠的、冗余的或者功能比较独立的测试,然后安全地将之删除。上面这些都是减少自动化测试误报告警、提高测试可分析性的积极有效的方法。另外,有一种错误的测试结果分析方法,那就是采用测试结果后处理程序对测试结果自动分析和过滤,尽管也可以采用这种测试结果分析方法,不过这种方法会使自动化测试系统复杂化,更重要的是,后处理程序中的 BUG 会严重损害自动化测试的完整性。如果由于自动化测试本身存在的缺陷误把产品中的正常功能视为异常,那该怎么办?我曾经看到测试小组花费开发测试自动化两倍的时间来修改测试脚本,并且不愿意开展培训过程。那些仅仅关注很浅层次测试技术的测试管理者对这种方法很感兴趣,他们排斥采用隐藏测试复杂度的方法。

      综上所述,应该集中精力关注可以延续使用的测试套,从以下几方面考虑,测试的可检视性、测试的可维护性、测试的完整性、测试的独立性、测试的可重复性。

      可读性: 很多情况下,在测试人员开始测试项目之前,公司已经有了一套测试脚本,并且已经存在很多年了。我们可以称之为 “ 聪明的橡树 ”(wise oak tree)[Bach 1996] 。大家很依赖它,但是并不知道它是什么。由于 “ 聪明的橡树 ” 类型的测试脚本缺乏可读性,在具体应用中,那些脚本常常没有多大的实用价值,越来越让人迷惑。因此,测试人员很难确定他们实际在测试什么,反而会导致测试人员对自身的测试能力有过高的估计。测试人员能够检视测试脚本,并且理解测试脚本究竟测试了什么,这是很关键的。好的文档是解决问题的手段之一,对测试脚本全面分析是另外一个手段。由上面两种方法可以引申出其它的相关方法,我曾经在一个项目中使用过引申之后的方法。在测试脚本中插桩,把所有执行的产品相关的命令记录到日志里。这样,当分析日志确定执行了哪些产品命令,命令采用了何种参数配置时,可以提供一个非常好的测试记录,里面记录了自动化测试执行了什么,没有执行什么。如果测试脚本可读性不好,很容易变得过分依赖并没有完全理解的测试脚本,很容易认为测试脚本实际上做的工作比你想象中的还要多。测试套的可读性提高后,可以更容易的开展同行评审活动。

      可维护性: 在工作中,我曾经使用过一个测试套,它把所有的程序输出保存到文件中。然后,通过对比输出文件内容和一个已有的输出文件内容的差别,可以称已有的输出文件为 “ 标准文件 ” ( “gold file” )。在回归测试中,用这个方法查找 BUG 是不是明智之举。这种方法太过于敏感了,它会产生很多错误的警告。随着时间的推移,软件开发人员会根据需要修改产品的很多输出信息,这会导致很多自动化测试失败。很明显,为了保证自动化测试的顺利进行,应该在对 “ 标准文件 ” 仔细分析的基础上,根据开发人员修改的产品输出信息对之做相应的修改。比较好的可维护性方法是,每次只检查选定的产品的某些特定输出,而不是对比所有的结果输出。产品的接口变动也会导致原来的测试无法执行或者执行失败。对于 GUI 测试,这是一个更大的挑战。研究由于产品接口变化引起的相关测试修改,并研究使测试修改量最小的方法,测试中采用库是解决问题的方法。当产品发生变化的时候,只需要修改相关的库,保证测试与产品的变动同步修改即可。

      完整性: 当自动化测试执行后,报告测试执行通过,可以断定这是真的吗?这就是我称之为测试套的完整性。在前面的故事中,当没有对自动化测试完整性给予应有的关注的时候,发生了富有喜剧性的情况。我们应该在多大程度上相信自动化化测试执行结果?自动化测试执行中的误报告警是很大的问题。测试人员特别讨厌由于测试脚本自身的问题或者是测试环境的问题导致测试执行失败,但是,对于自动化测试误报告警的情况,大家往往无能为力。你期望自己设计的测试对 BUG 很敏感、有效,当测试发现异常的时候,能够报告测试执行失败。有的测试框架支持对特殊测试结果的分类方法,分类包括 PASS , FAIL 和第三种测试结果 NOTRUN 或者 UNRESOLVED 。无论你怎么称呼第三种测试结果,它很好的说明了由于某些测试失败导致其他测试用例无法执行而并非执行失败的情况。得到正确的测试结果是自动化测试完整性定义的一部分,另一部分是能够确认执行成功的测试确确实实已经执行过了。我曾经在一个测试队列中发现一个 BUG ,这个 BUG 引起测试队列中部分测试用例被跳过,没有执行。当测试队列运行完毕后,没有上报任何错误,我不得不通过走读代码的方式发现了这个 BUG 。如果,我没有关注到这个 BUG ,那么可能在认识到自动化测试已经出现问题之前,还在长时间运行部分测试用例。

      独立性: 采用自动化方法不可能达到和手工测试同样的效果。当写手工测试执行的规程时候,通常假定测试执行将会由一个有头脑、善于思考、具有观察力的测试人员完成的。如果采用自动化,测试执行是由一台不会说话的计算机完成的,你必须告诉计算机什么样的情况下测试执行是失败的,并且需要告诉计算机如何恢复测试场景才能保证测试套可以顺利执行。自动化测试可以作为测试套的一部分或者作为独立的测试执行。测试都需要建立自己所需要的测试执行环境,因此,保证测试执行的独立性是唯一的好方法。手工回归测试通常都相关的指导文档,以便一个接着一个有序地完成测试执行,每个测试执行可以利用前一个测试执行创建的对象或数据记录。手工测试人员可以清楚地把握整个测试过程。在自动化测试中采用上述方法是经常犯的错误,这个错误源于 “ 多米诺骨牌 ” 测试套,当一个测试执行失败,会导致后续一系列测试失败。更糟糕的是,所有的测试关联紧密,无法独立的运行。并且,这使得在自动化测试中分析合法的执行失败结果也困难重重。当出现这种情况后,人们首先开始怀疑自动化测试的价值。自动化测试的独立性要求在自动化测试中增加重复和冗余设计。具有独立性的测试对发现的缺陷的分析有很好的支持。以这种方式设计自动化测试好像是一种低效率的方式,不过,重要的是在不牺牲测试的可靠性的前提下保证测试的独立性,如果测试可以在无需人看守情况下运行,那么测试的执行效率就不是大问题了。

      可重复性: 自动化测试有时能够发现问题,有时候又无法发现问题,对这种情况实在没有什么好的的处理办法。因此,需要保证每次测试执行的时候,测试是以同样的方式工作。这意味着不要采用随机数据,在通用语言库中构造的随机数据经常隐藏初始化过程,使用这些数据会导致测试每次都以不同的方式执行,这样,对测试执行的失败结果分析是很让人沮丧的。这里有两个使用随机数据发生器的的方法可以避免上述情况。一种方法是使用常量初始化随机数据发生器。如果你打算生成不同种类的测试,需要在可预测,并且可控制的情况下建立不同类型的随机数据发生器。另外一个办法是提前在文件中或数据库中建立生成随机测试数据,然后在测试过程中使用这些数据。这样做看起来似乎很好,但是我却曾经看到过太多违反规则的做法。下面我来解释到底看到了什么。当手动执行测试的时候,往往匆匆忙忙整理文件名和测试数据记录。当对这些测试采用自动化测试方法,该做哪些工作呢?办法之一是,可以为测试中使用的数据记录给固定的命名。如果这些数据记录在测试完成后还要继续使用,那么就需要制定命名规则,避免在不同的测试中命名冲突,采用命名规则是一种很好的方法。然而,我曾经看到有些测试只是随机的命名数据记录,很不幸,事实证明采用这种随机命名的方式不可避免的导致命名冲突,并且影响测试的可重复性。很显然,自动化工程师低估了命名冲突的可能性。下面的情况我遇到过两次,测试数据记录的名字中包含四个随机产生的数字,经过简单的推算如果我们采用这种命名方式的时候,如果测试使用了 46 条记录,会存在 10% 冲突的可能性,如果使用 118 条记录,冲突的几率会达到 50% 。我认为测试当中使用这种随机命名是出于偷懒的想法 —— 避免再次测试之前写代码清除老的数据记录,这样引入了问题,损害了测试的可靠性和测试的完整性。

      测试库: 自动化测试的一个通用策略是开发可以在不同测试中应用的测试函数库。我曾经看到过很多测试函数库,自己也写了一些。当要求测试不受被测试产品接口变动影响的时候,采用测试库方法是非常有效的。不过,根据我的观察测试库已经使用的太多了,已经被滥用了,并且测试库往往设计的不好,没有相关的文档支撑,因此,使用测试库的测试往往很难开展。当发现问题的时候,往往不知道是测试库自身的问题,还是测试库的使用问题。由于测试库往往很复杂,即便在发现测试库存在问题,相关的维护人员也很不愿意去修改问题。通过前文中的论述,可以得出结论,在一开始就应该保证测试库设计良好。但是,实际情况是测试自动化往往没有花费更多的精力去保证一个优良设计的测试库。我曾经看到有些测试库中的功能根本不再使用了或仅仅使用一次。这与极限编程原则保持一致,即 " 你将不需要它 " 。这会导致在测试用例之间的代码出现一些重复,我发现微小的变化可能仍然存在,很难与测试库功能协调。你可能打算对测试用例作修改,采用源代码的方式比采用库的方式更容易修改。如果有几个测试,他们有某些共同的操作,我使用剪切和粘贴的方式去复制代码,有的人认为我采用的方法不可理喻。这允许我根据需要修改通用代码,我不必一开始尝试和猜测如何重用代码。我认为我的测试是很容易读懂的,因为阅读者不必关心任何测试库的语法。这种办法的优势是很容易理解测试,并且很方便扩展测试套。在开发软件测试项目的时候,大多数程序员找到与他们打算实现功能类似的源代码,并对源代码做修改,而不是从头开始写代码。同样,在写测试套的过程中可以采用上述方法,这也是代码开发方式所鼓励的方法。我比较喜欢写一些规模比较小的测试库,这些库可以被反复的使用。测试库的开发需要在概念阶段充分定义,并且文档化,从始至终都应该保持。我会对测试库作充分的测试后,才在测试中使用这些测试库。采用测试库是对所有面临的情况作权衡的。千万不要打算写一个大而全的测试库,不要希望有朝一日测试人员会利用你的测试库完成大量的测试,这一天恐怕永远不会到来。

      数据驱动测试: 把测试数据写入到简单表格中,这种测试技术得到了越来越广泛的应用,这种方法被称为表驱动( table-driven ),数据驱动 (data-driven) 或者 “ 第三代 ” 自动化测试( "third generation" automation )。这需要写一个解析器,用来解释表格中的数据,并执行测试。该测试架构的最主要的好处是,它允许把测试内容写在具有一定格式的表格中,这样方便数据设计和数据的检视。如果测试组中有缺少编程经验的业务专家参与测试,采用数据驱动测试方法是很合适的。数据驱动测试的解析器主要是由测试库和上层的少量开发语言写成的代码组成的,所以,上面关于测试库的说明放在这里是同样合适的。在针对上面提到的少量代码的设计、开发、测试的工作,还存在各种困难。代码所采用的编程语言是不断发展的。也许,测试人员认为他们需要把第一部分测试的输出作为第二部分测试的输入,这样,加入了新的变量。接下来,也许有人需要让测试中的某个环节运行一百次,这样加入一个循环。你可以采用其他语言,不过,如果你预料到会面临上述情况的时候,那么做好采用一些能够通过公开的渠道获取的编程语言,比如 Perl,Python 或者 TCL ,这样比设计你自己的语言要快的多。

      启发式确认: 我曾经看到很多测试自动化没有真正意义上的结果校验,其原因有两个,一个原因是做完全意义上的自动化测试结果确认从技术上讲是很困难的,另外一个原因是通过测试设计规格很难找出自动化测试的预期结果。这很不幸。不过,采用手工校验测试结果的方法是真正意义上的测试校验。标准文件( Gold file )是另外一中校验测试结果的方法。首先,捕获被测试程序的输出,并检视程序的输出,然后,把输出信息文档化,并归档,作为标准文件。以后,自动化测试结果与标准文件作比较,从而达到结果校验的目的。采用标准文件的方法,也有弊端。当产品发生变化,自动化测试的环境配置发生变化,产品的输出发生变化的时候,采用标准文方法,会上报大量的误报告警。做好的测试结果校验方法是,对输出结果的特定内容作分析,并作合理的比较。有时候,很难知道正确的输出结果是什么样的,但是你应该知道错误的输出结果是什么样的。开展启发式的结果校验是很有帮助的。我猜想一些人在自动化测试中设计了大而全的测试结果校验方法,是因为担心如果结果校验漏掉了任何信息,可能导致自动化测试自身出现错误。不过,我们在测试过程中往往采用折衷的做法,没有采用大而全的测试结果校验方法,这样就不得不面对少量漏测情况的出现的风险。自动化测试不能改变这种情况的出现。如果自动化工程师不习惯采用这种折衷的方法,那么他必须找相关人员咨询,寻找一种合适的测试结果校验策略,这需要有很大的创造性。目前有很多技术可以保证在不产生误报告警的情况下,找到被测试产品的缺陷。

      把注意力放在通过设计保证测试的可延续性上,选择一个合适的测试体系架构,你将进一步迈向成功的自动化测试。

      步骤六:有计划的部署

      在前面的故事中,当自动化工程师没有提供打包后的自动化测试程序给测试执行人员,会影响到测试执行,测试执行人员不得不反过来求助自动化工程师指出如何使用自动化测试程序。

      作为自动化工程师,你知道如何利用自动化方法执行测试和分析执行失败的结果。不过,测试执行人员却未必知道如何使用自动化测试。因此,需要提供自动化测试程序的安装文档和使用文档,保证自动化测试程序容易安装和配置。当安装的环境与安装的要求不匹配,出现安装错误的时候,能够给出有价值的提示信息,便于定位安装问题。

      能够把自动化测试程序和测试套作为产品对待,那真是太好了。你应该对自动化测试程序和测试套开展测试,保证它们不依赖于任何专用的库或者是设备上的任何其他程序。

      保证其他测试人员能够随时利用已经提供的自动化测试程序和测试套开展测试工作;保证自动化测试是符合一般测试执行人员的思维习惯的;保证测试执行人员能够理解测试结果,并能够正确分析失败的测试执行结果;这需要自动化工程师提供自动动化测试相关的指导性文档和培训。

      作为测试管理者,你希望在自动化工程师离开前,能够识别并修改测试套中的所有问题。自动化工程师迟早会离开的,如果你没有及时的把测试套中的问题提出来,就会面临废弃已有的测试套的决定。

      良好的测试套有多方面的用处。良好的测试套支持对产品新版本的测试;良好的测试套在新的软件平台上可以很方便的验证产品的功能;良好的测试套支持每天晚上开始的软件每日构造过程;甚至开发人员在代码 check in 之前,用良好的测试套验证代码的正确性。

      测试套的共享也很重要。很难预见以后什么人会继续使用你开发的测试套。因此,尽量让产品开发测试团队中的成员都很容易获得你的测试套。可以把测试套放在公司的内部网络上,这是个很好的办法。这样,大家就不必为了获取一份需要的测试套而四处打听。有些人总是感觉自己的测试套还没有最终完工或者不够完美,而没有拿出来与人分享,这种做法一定要改变,共享出来的测试套不一定非常完美,共享才是关键。

      有计划的自动化测试部署,保证你的测试套能够被产品相关人员获取到,你就向成功的自动化测试又迈进了一步。并且你的自动化测试会被一次又一次的重用。

      步骤七:面对成功的挑战

      当你完成了所有的事情,测试套已经文档化了,并且文档已经交付了。测试执行人员能够理解要开展的测试,并知道如何完成测试执行。随着你所负责产品的进一步开发和维护,测试被反复重用。虽然,在自动化使测试变简单的同时,也总是使测试过程复杂化。测试人员需要学习如何诊断自动化测试执行失败的情况,如果不这样做,测试执行人员会认为执行失败的情况是由自动化引起,然后,自动化工程师被叫过来帮助诊断每一个执行失败的情况,开发人员往往也会认为执行失败是由于自动化测试自身引起的问题,这样,测试执行人员就不得不学习通过手工的方式,或者通过采用少量脚本的方式重现自动化测试发现的问题,以证明他们确实发现了产品当中的 BUG 。

      测试套的相关工作还没有结束,为了提高测试覆盖率或者测试新的产品特性,需要增加更多的测试。如果已有的测试不能正常工作,那么需要对之修改;如果已有的测试是冗余的,那么需要删除这部分测试。

      随着时间的推移,开发人员也会研究你设计的测试,改进产品的设计并且通过模拟你的测试过程对产品做初步测试,研究如何使产品在第一次测试就通过,这样,你设计的测试很可能无法继续发现新的问题,这种现象被称为一种杀虫剂悖论。这时候,会有人对你的测试有效性提出质疑,那么,你必须考虑是否应该挖掘更严格的测试,以便能够发现开发人员优化之后的产品中的缺陷。

      以前,我提到过一个基本上无法实现的设想,设想通过按下一个按钮就完成了所有的测试工作。自动化测试是不是全能的,手工测试是永远无法完全替代的。

      有些测试受测试环境的影响很大,往往需要采用人工方法获取测试结果,分析测试结果。因此,很难在预先知道设计的测试用例有多大的重用性。自动化测试还需要考虑成本问题,因此,千万不要陷入到一切测试都采用自动化方法的错误观念中。

      我曾经主张保证给与测试自动化持续不断的投入。但是,在开展自动化测试的时候,一个问题摆在面前,测试自动化应该及时的提供给测试执行人员,这个不成问题,但是如何保证需求变更后,能够及时提供更新后的自动化测试就是个大问题了。如果自动化测试与需求变更无法同步,那么自动化测试的效果就无法保证了,测试人员就不愿意花费时间学习如何使用新的测试工具和如何诊断测试工具上报的错误。识别项目计划中的软件发布日期,然后把这个日期作为里程碑,并计划达到这个里程碑。当达到这个里程碑后,自动化工程师应该做什么呢?如果自动化工程师关注当前产品版本的发布,他需要为测试执行人员提供帮助和咨询,但是,一旦测试执行人员知道如何使用自动化测试,自动化测试工程师可以考虑下一个版本的测试自动化工作,包括改进测试工具和相关的库。当开发人员开始设计产品下一个版本中的新特性的时候,如果考虑了自动化测试需求,那么自动化测试师的设计工作就很好开展了,采用这种方法,自动化测试工程师可以保持与开发周期同步,而不是与测试周期同步。如果不采用这种方式,在产品版本升级的过程中,自动化测试无法得到进一步的改进。

      持续在在自动化投入,你会面临成功的挑战,当自动化测试成为测试过程可靠的基础后,自动化测试的道路将会越来越平坦。

      参考文献:

      Bach, James. 1996. “Test Automation Snake Oil.” Windows Technical Journal , (October): 40-44. http://www.satisfice.com/articles/test_automation_snake_oil.pdf

      Dustin, Elfriede. 1999. “Lessons in Test Automation.” Software Testing and Quality Engineering (September): 16-22.
    http://www.stickyminds.com/sitewide.asp?ObjectId=1802&ObjectType=ART&Function=edetail

      Fewster, Mark and Dorothy Graham. 1999. Software Test Automation , Addison-Wesley.

      Groder, Chip. “Building Maintainable GUI Tests” in [Fewster 1999].

      Kit, Edward. 1999. “Integrated, Effective Test Design and Automation.” Software Development (February). http://www.sdmagazine.com/articles/1999/9902/9902b/9902b.htm

      Hancock, Jim. 1997 “When to Automate Testing.” Testers Network (June).
    http://www.data-dimensions.com/Testers'Network/jimauto1.htm

      Hendrickson, Elisabeth. 1999. “Making the Right Choice: The Features you Need in a GUI Test Automation Tool.” Software Testing and Quality Engineering Magazine (May): 21-25. http://www.qualitytree.com/feature/mtrc.pdf

      Hoffman, Douglas. 1999. “Heuristic Test Oracles: The Balance Between Exhaustive Comparison and No Comparison at All.” Software Testing and Quality Engineering Magazine (March): 29-32.

      Kaner, Cem. 1997. “Improving the Maintainability of Automated Test Suites.” Presented at Quality Week. http://www.kaner.com/lawst1.htm

      Linz , Tilo and Matthias Daigl. 1998. “How to Automate Testing of Graphical User Interfaces.” European Systems and Software Initiative Project No. 24306 (June). http://www.imbus.de/html/GUI/AQUIS-full_paper-1.3.html

      Jeffries, Ronald E., 1997, “XPractices,”
    http://www.XProgramming.com/Practices/xpractices.htm

      Marick, Brian. 1998. “When Should a Test Be Automated?” Presented at Quality Week. http://www.testing.com/writings/automate.pdf

      Marick, Brian. 1997. “Classic Testing Mistakes.” Presented at STAR. http://www.testing.com/writings/classic/mistakes.html

      Pettichord, Bret. 1996. “Success with Test Automation.” Presented at Quality Week (May). http://www.io.com/~wazmo/succpap.htm

      Thomson, Jim. “A Test Automation Journey” in [Fewster 1999]

      Weinberg, Gerald M. 1992. Quality Software Management: Systems Thinking . Vol 1. Dorset House.



     

    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=651566

  • 智能手机小应用常见故障总结

    2007-10-23 09:47:49

    最近一直在做智能手机小应用的跟踪验证测试,故障单是由测试高手提供的,是一个非常完善的测试队,连我们的开发团队都感叹他们的敏锐,能发现潜在的Bug。

       在验证之余,我认真研究了他们出的故障单,做了一些总结。

       1、手机软件系统测试的角度分为:功能模块测试,交叉事件测试,压力测试,容量性能测试,性能测试和用户手册测试等。

       2、功能模块测试:首先应分析功能模块的功能项,测试每个功能项是否能够实现对应的功能。一般根据测试案例(Test Case)或软件本身的流程就可以完成基本功能测试。(相对简单,故障也较容易解决)

       3、交叉事件测试:又叫事件或冲突测试,是指一个功能正在执行过程中,同时另外一个事件或操作对该过程进行干扰的测试。例如通话过程中接收到短信或来响闹。应该以执行干扰的冲突事件不会导致手机死机或花屏等严重的问题。
       交叉事件测试非常重要,能发现很多应用中潜在的性能问题。另外有中英文模式的切换的手机要注意中英文模式切换后的功能实现存在的问题,通常会被测试人没忽略。

       4、压力测试:又叫边界值容错测试或极限负载测试,即测试过程中,已经达到某一软件功能的最大容量,边界值或最大的承载极限,仍然对其进行相关操作。例如连续进行短信的接收和发送,超过收件箱和PIM卡所能存储的最大的条数,仍然进行短消息的接收或发送,以检测软件在超常态条件下的表现,来评估用户能否接受。
       压力测试用手工测试非常繁锁,可以考虑自动化测试,目前没有比较大量使用的工具,一般都是由开发人员配合开发出的工具,或者高级的测试人员编写出的脚本。

       5、容量测试:又叫满记忆体测试,包括手机的用户可用内存和SIM/PIM卡的所有空间被完全使用的测试。此时再对可编辑的模块进行和存储空间有关的任何操作测试,如果软件的极限容量状态下处理不好,有可能导致死机或严重的花屏等问题的出现。
       与压力测试有些类似,也可考虑自动化测试。

       6、兼容性测试:也就是不同品牌手机,不同网络,不同品牌和不同容量大小的SIM/PIM卡之间的互相兼容的测试,以短消息为例:中国电信的小灵通接收到从中国移动或中国联通GSM发来的短消息,接收,显示和回复功能是否正常等

       另外从我测试的这几个小模块中,按与时间相关和文字两方面容易出现故障的地方总结如下:

       1、与时间相关:首先是时间的输入域,是否有输入限制,如:文字、标点符号、小时大于24或12、分钟大于60、秒大于60、月大于12、日大于31(按月情况而定)等
       特别注意日期变更分界点如23:59或12:59的变化。以及12/24小时切换模式的测试。

       2、文字输入相关:当界面过多时,注意功能按钮的点击事件能否正常完成相应功能的实现。超过文字字数限制时的系统提示等。

  • Alpha和Beta测试简介

    2007-10-23 09:44:01

    大型通用软件,在正式发布前,通常需要执行Alpha和Beta测试,目的是从实际终端用户的使用角度,对软件的功能和性能进行测试,以发现可能只有最终用户才能发现的错误。
    Alpha测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的受控测试,Alpha测试不能由程序员或测试员完成。Alpha测试发现的错误,可以在测试现场立刻反馈给开发人员,由开发人员及时分析和处理。目的是评价软件产品的功能、可使用性、可靠性、性能和支持。尤其注重产品的界面和特色。Alpha测试可以从软件产品编码结束之后开始,或在模块(子系统)测试完成后开始,也可以在确认测试过程中产品达到一定的稳定和可靠程度之后再开始。有关的手册(草稿)等应该在Alpha测试前准备好。

    Beta测试是软件的多个用户在一个或多个用户的实际使用环境下进行的测试。开发者通常不在测试现场,Beta测试不能由程序员或测试员完成。因而, Beta测试是在开发者无法控制的环境下进行的软件现场应用。在Beta测试中,由用户记下遇到的所有问题,包括真实的以及主管认定的,定期向开发者报告,开发者在综合用户的报告后,做出修改,最后将软件产品交付给全体用户使用。Beta测试着重于产品的支持性,包括文档、客户培训和支持产品的生产能力。只有当Alpha测试达到一定的可靠程度后,才能开始Beta测试。由于Beta测试的主要目标是测试可支持性,所以Beta测试应该尽可能由主持产品发行的人员来管理。
    
    _
    由于Alpha和Beta测试的组织难度大,测试费用高,测试的随机性强、测试周期跨度较长,测试质量和测试效率难于保证,所以,很多专业软件可能不再进行Beta测试。随着测试技术的提高,以及专业测试服务机构的大量涌现,很多软件的Beta测试外包给这些专业测试机构进行测试。 
  • 软件测试步骤

    2007-10-23 09:38:28

    软件测试步骤

    2007-08-08 15:06:49 / 个人分类:软件测试技术

     测试过程按4个步骤进行,即单元测试、集成测试、确认测试和系统测试及发版测试。
    •   
    开始是单元测试,集中对用源代码实现的每一个程序单元进行测试,检查各个程序模块是否正确地实现了规定的功能。
      
      
      
    •     
    集成测试把已测试过的模块组装起来,主要对与设计相关的软件体系结构的构造进行测试。
    •     
    确认测试则是要检查已实现的软件是否满足了需求规格说明中确定了的各种需求,以及软件配置是否完全、正确。
    •     
    系统测试把已经经过确认的软件纳入实际运行环境中,与其它系统成份组合在一起进行测试。
    单元测试 (Unit Testing)
    •     
    单元测试又称模块测试,是针对软件设计的最小单位程序模块,进行正确性检验的测试工作。其目的在于发现各模块内部可能存在的各种差错。
    •     
    单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立进行单元测试。
    1.
    单元测试的内容
    •     
    在单元测试时,测试者需要依据详细设计说明书和源程序清单,了解该模块的I/O条件和模块的逻辑结构,主要采用白盒测试的测试用例,辅之以黑盒测试的测试用例,使之对任何合理的输入和不合理的输入,都能鉴别和响应。


      
    (1)
    模块接口测试
    •   
    在单元测试的开始,应对通过被测模块的数据流进行测试。测试项目包括:
    –   
    调用本模块的输入参数是否正确;
    –   
    本模块调用子模块时输入给子模块的参数是否正确;
    –   
    全局量的定义在各模块中是否一致;


      
    •     
    在做内外存交换时要考虑:
      
    –   
    文件属性是否正确;
    –   OPEN
    CLOSE语句是否正确;
    –   
    缓冲区容量与记录长度是否匹配;
    –   
    在进行读写操作之前是否打开了文件;
    –   
    在结束文件处理时是否关闭了文件;
    –   
    正文书写/输入错误,
    –   I
    O错误是否检查并做了处理。


    (2)
    局部数据结构测试
    •     
    不正确或不一致的数据类型说明
    •     
    使用尚未赋值或尚未初始化的变量
    •     
    错误的初始值或错误的缺省值
    •     
    变量名拼写错或书写错
    •     
    不一致的数据类型
    •     
    全局数据对模块的影响
    (3)
    路径测试
    •   
    选择适当的测试用例,对模块中重要的执行路径进行测试。
    •   
    应当设计测试用例查找由于错误的计算、不正确的比较或不正常的控制流而导致的错误。
    •   
    对基本执行路径和循环进行测试可以发现大量的路径错误。
    (4)
    错误处理测试
    •     
    出错的描述是否难以理解
    •     
    出错的描述是否能够对错误定位
    •     
    显示的错误与实际的错误是否相符
    •     
    对错误条件的处理正确与否
    •     
    在对错误进行处理之前,错误条件是否已经引起系统的干预等
    (5)
    边界测试
    •     
    注意数据流、控制流中刚好等于、大于或小于确定的比较值时出错的可能性。对这些地方要仔细地选择测试用例,认真加以测试。
    •     
    如果对模块运行时间有要求的话,还要专门进行关键路径测试,以确定最坏情况下和平均意义下影响模块运行时间的因素。


      
      
      
    2.
    单元测试的步骤
    •   
    模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些辅助模块去模拟与被测模块相联系的其它模块。
    –   
    驱动模块 (driver)
    –   
    桩模块 (stub) ── 存根模块
      
      
      
      
    •      
    如果一个模块要完成多种功能,可以将这个模块看成由几个小程序组成。必须对其中的每个小程序先进行单元测试要做的工作,对关键模块还要做性能测试
    •      
    对支持某些标准规程的程序,更要着手进行互联测试。有人把这种情况特别称为模块测试,以区别单元测试。
    集成测试(Integrated Testing
    •     
    集成测试 (集成测试、联合测试)
    •     
    通常,在单元测试的基础上,需要将所有模块按照设计要求组装成为系统。这时需要考虑的问题是:
    –   
    在把各个模块连接起来的时侯,穿越模块接口的数据是否会丢失;
    –   
    一个模块的功能是否会对另一个模块的功能产生不利的影响;


      
    –   
    各个子功能组合起来,能否达到预期要求的父功能;
    –   
    全局数据结构是否有问题;
    –   
    单个模块的误差累积起来,是否会放大,从而达到不能接受的程度。
    在单元测试的同时可进行集成测试,
    发现并排除在模块连接中可能出现
    的问题,最终构成要求的软件系统。





    •   
    子系统的集成测试特别称为部件测试,它所做的工作是要找出集成后的子系统与系统需求规格说明之间的不一致。
    •   
    通常,把模块集成成为系统的方式有两种
    –   
    一次性集成方式
    –   
    增殖式集成方式


    1.
    一次性集成方式(big bang)
    •   
    它是一种非增殖式组装方式。也叫做整体拼装。
    •   
    使用这种方式,首先对每个模块分别进行模块测试,然后再把所有模块组装在一起进行测试,最终得到要求的软件系统。
      
    2.
    增殖式集成方式
    •     
    这种集成方式又称渐增式集成
    •     
    首先对一个个模块进行模块测试,然后将这些模块逐步组装成较大的系统
    •     
    在集成的过程中边连接边测试,以发现连接过程中产生的问题
    •     
    通过增殖逐步组装成为要求的软件系统。


    (1)
    自顶向下的增殖方式
    •      
    这种集成方式将模块按系统程序结构,沿控制层次自顶向下进行组装。
    •      
    自顶向下的增殖方式在测试过程中较早地验证了主要的控制和判断点。
    •      
    选用按深度方向组装的方式,可以首先实现和验证一个完整的软件功能。
      
    (2)
    自底向上的增殖方式
    •     
    这种集成的方式是从程序模块结构的最底层的模块开始集成和测试。
    •     
    因为模块是自底向上进行组装,对于一个给定层次的模块,它的子模块(包括子模块的所有下属模块)已经组装并测试完成,所以不再需要桩模块。在模块的测试过程中需要从子模块得到的信息可以直接运行子模块得到。


      
    •   
    自顶向下增殖的方式和自底向上增殖的方式各有优缺点。
    •   
    一般来讲,一种方式的优点是另一种方式的缺点。
    (3)
    混合增殖式测试
    •   
    衍变的自顶向下的增殖测试
    –   
    首先对输入/输出模块和引入新算法模块进行测试;
    –   
    再自底向上组装成为功能相当完整且相对独立的子系统;
    –   
    然后由主模块开始自顶向下进行增殖测试。
      
    •   
    自底向上-自顶向下的增殖测试
    –   
    首先对含读操作的子系统自底向上直至根结点模块进行组装和测试;
    –   
    然后对含写操作的子系统做自顶向下的组装与测试。
    •   
    回归测试
    –   
    这种方式采取自顶向下的方式测试被修改的模块及其子模块;
    –   
    然后将这一部分视为子系统,再自底向上测试。
    关键模块问题
    •     
    在组装测试时,应当确定关键模块,对这些关键模块及早进行测试。
    •     
    关键模块的特征:
    满足某些软件需求;
    在程序的模块结构中位于较高的层次(高层控制模块);
    较复杂、较易发生错误;
    有明确定义的性能要求。


    确认测试(Validation Testing
    •   
    确认测试又称有效性测试。任务是验证软件的功能和性能及其它特性是否与用户的要求一致。
    •   
    对软件的功能和性能要求在软件需求规格说明书中已经明确规定。它包含的信息就是软件确认测试的基础。
      
    1.
    进行有效性测试(黑盒测试)
    •     
    有效性测试是在模拟的环境 (可能就是开发的环境) 下,运用黑盒测试的方法,验证被测软件是否满足需求规格说明书列出的需求。
    •     
    首先制定测试计划,规定要做测试的种类。还需要制定一组测试步骤,描述具体的测试用例。
      
    •   
    通过实施预定的测试计划和测试步骤,确定
    –   
    软件的特性是否与需求相符;
    –   
    所有的文档都是正确且便于使用;
    –   
    同时,对其它软件需求,例如可移植性、兼容性、出错自动恢复、可维护性等,也都要进行测试
      
    •     
    在全部软件测试的测试用例运行完后,所有的测试结果可以分为两类:
    –   
    测试结果与预期的结果相符。这说明软件的这部分功能或性能特征与需求规格说明书相符合,从而这部分程序被接受。
    –   
    测试结果与预期的结果不符。这说明软件的这部分功能或性能特征与需求规格说明不一致,因此要为它提交一份问题报告。


    2.
    软件配置复查
    n      
    软件配置复查的目的是保证
    u  
    软件配置的所有成分都齐全;
    u  
    各方面的质量都符合要求;
    u  
    具有维护阶段所必需的细节;
    u  
    而且已经编排好分类的目录。
    n  
    应当严格遵守用户手册和操作手册中规定的使用步骤,以便检查这些文档资料的完整性和正确性。
    验收测试(Acceptance Testing
    •     
    在通过了系统的有效性测试及软件配置审查之后,就应开始系统的验收测试。
    •     
    验收测试是以用户为主的测试。软件开发人员和QA(质量保证)人员也应参加。
    •     
    由用户参加设计测试用例,使用生产中的实际数据进行测试。
      
    •   
    在测试过程中,除了考虑软件的功能和性能外,还应对软件的可移植性、兼容性、可维护性、错误的恢复功能等进行确认。
    •   
    确认测试应交付的文档有:
    –   
    确认测试分析报告
    –   
    最终的用户手册和操作手册
    –   
    项目开发总结报告。

    系统测试(System Testing
    •     
    系统测试,是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、某些支持软件、数据和人员等其它系统元素结合在一起,在实际运行环境下,对计算机系统进行一系列的组装测试和确认测试。
    •     
    系统测试的目的在于通过与系统的需求定义作比较,  发现软件与系统的定义不符合或与之矛盾的地方。

    α
    测试和β测试
    •   
    在软件交付使用之后,用户将如何实际使用程序,对于开发者来说是无法预测的。
    •    α
    测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的测试。
      
    •     α
    测试的目的是评价软件产品的FLURPS(即功能、局域化、可使用性、可靠性、性能和支持)。尤其注重产品的界面和特色。
    •     α
    测试可以从软件产品编码结束之时开始,或在模块(子系统)测试完成之后开始,也可以在确认测试过程中产品达到一定的稳定和可靠程度之后再开始。


      
    •     β
    测试是由软件的多个用户在实际使用环境下进行的测试。这些用户返回有关错误信息给开发者。 查看(649) 评论(0) 收藏 分享 管理

  • 如何设计编写软件测试用例

    2007-10-23 09:35:28

    随着中国软件业的日益壮大和逐步走向成熟,软件测试也在不断发展:从最初的由软件编程人员兼职测试到软件公司组建独立专职测试部门;测试工作也从简单测试演变为包括编制测试计划、编写测试用例、准备测试数据、开发测试脚本、实施测试、测试评估等多项内容的正规测试;测试方式则由单纯手工测试发展为手工、自动兼之,并有向第三方专业测试公司发展的趋势。

    一、测试用例是软件测试的核心

           软件测试的重要性是毋庸置疑的。但如何以最少的人力、资源投入,在最短的时间内完成测试,发现软件系统的缺陷,保证软件的优良品质,则是软件公司探索和追求的目标。每个软件产品或软件开发项目都需要有一套优秀的测试方案和测试方法。

           影响软件测试的因素很多,例如软件本身的复杂程度、开发人员(包括分析、设计、编程和测试的人员)的素质、测试方法和技术的运用等等。因为有些因素是客观存在的,无法避免。有些因素则是波动的、不稳定的,例如开发队伍是流动的,有经验的走了,新人不断补充进来;一个具体的人工作也受情绪等影响,等等。如何保障软件测试质量的稳定?有了测试用例,无论是谁来测试,参照测试用例实施,都能保障测试的质量。可以把人为因素的影响减少到最小。即便最初的测试用例考虑不周全,随着测试的进行和软件版本更新,也将日趋完善。

           因此测试用例的设计和编制是软件测试活动中最重要的。测试用例是测试工作的指导,是软件测试的必须遵守的准则,更是软件测试质量稳定的根本保障。

    二、什么叫测试用例

           测试用例(Test Case)目前没有经典的定义。比较通常的说法是:指对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略,内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,并形成文档。

           不同类别的软件,测试用例是不同的。不同于诸如系统、工具、控制、游戏软件,管理软件的用户需求更加不统一,变化更大、更快。笔者主要从事企业管理软件的测试。因此我们的做法是把测试数据和测试脚本从测试用例中划分出来。测试用例更趋于是针对软件产品的功能、业务规则和业务处理所设计的测试方案。对软件的每个特定功能或运行操作路径的测试构成了一个个测试用例。

    三、编写测试用例

           着重介绍一些编写测试用例的具体做法。

    1、测试用例文档

           编写测试用例文档应有文档模板,须符合内部的规范要求。测试用例文档将受制于测试用例管理软件的约束。

           软件产品或软件开发项目的测试用例一般以该产品的软件模块或子系统为单位,形成一个测试用例文档,但并不是绝对的。

           测试用例文档由简介和测试用例两部分组成。简介部分编制了测试目的、测试范围、定义术语、参考文档、概述等。测试用例部分逐一列示各测试用例。每个具体测试用例都将包括下列详细信息:用例编号、用例名称、测试等级、入口准则、验证步骤、期望结果(含判断标准)、出口准则、注释等。以上内容涵盖了测试用例的基本元素:测试索引,测试环境,测试输入,测试操作,预期结果,评价标准。

    2、测试用例的设置

          我们早期的测试用例是按功能设置用例。后来引进了路径分析法,按路径设置用例。目前演变为按功能、路径混合模式设置用例。

          功能测试是最简捷的,按用例规约遍历测试每一功能。

          对于复杂操作的程序模块,其各功能的实施是相互影响、紧密相关、环环相扣的,可以演变出数量繁多的变化。没有严密的逻辑分析,产生遗漏是在所难免。路径分析是一个很好的方法,其最大的优点是在于可以避免漏测试。

          但路径分析法也有局限性。在一个非常简单字典维护模块就存在十余条路径。一个复杂的模块会有几十到上百条路径是不足为奇的。笔者以为这是路径分析比较合适的使用规模。若一个子系统有十余个或更多的模块,这些模块相互有关联。再采用路径分析法,其路径数量成几何级增长,达5位数或更多,就无法使用了。那么子系统模块间的测试路径或测试用例还是要靠传统方法来解决。这是按功能、路径混合模式设置用例的由来。

    3、设计测试用例

          测试用例可以分为基本事件、备选事件和异常事件。设计基本事件的用例,应该参照用例规约(或设计规格说明书),根据关联的功能、操作按路径分析法设计测试用例。而对孤立的功能则直接按功能设计测试用例。基本事件的测试用例应包含所有需要实现的需求功能,覆盖率达100%

          设计备选事件和异常事件的用例,则要复杂和困难得多。例如,字典的代码是唯一的,不允许重复。测试需要验证:字典新增程序中已存在有关字典代码的约束,若出现代码重复必须报错,并且报错文字正确。往往在设计编码阶段形成的文档对备选事件和异常事件分析描述不够详尽。而测试本身则要求验证全部非基本事件,并同时尽量发现其中的软件缺陷。

          可以采用软件测试常用的基本方法:等价类划分法、边界值分析法、错误推测法、因果图法、逻辑覆盖法等设计测试用例。视软件的不同性质采用不同的方法。如何灵活运用各种基本方法来设计完整的测试用例,并最终实现暴露隐藏的缺陷,全凭测试设计人员的丰富经验和精心设计。

    四、测试用例在软件测试中的作用

    1、指导测试的实施

           测试用例主要适用于集成测试、系统测试和回归测试。在实施测试时测试用例作为测试的标准,测试人员一定要按照测试用例严格按用例项目和测试步骤逐一实施测试。并对测试情况记录在测试用例管理软件中,以便自动生成测试结果文档。

           根据测试用例的测试等级,集成测试应测试那些用例,系统测试和回归测试又该测试那些用例,在设计测试用例时都已作明确规定,实施测试时测试人员不能随意作变动。

    2、规划测试数据的准备

           在我们的实践中测试数据是与测试用例分离的。按照测试用例配套准备一组或若干组测试原始数据,以及标准测试结果。尤其象测试报表之类数据集的正确性,按照测试用例规划准备测试数据是十分必须的。

          除正常数据之外,还必须根据测试用例设计大量边缘数据和错误数据。

    3、编写测试脚本的"设计规格说明书"

          为提高测试效率,软件测试已大力发展自动测试。自动测试的中心任务是编写测试脚本。如果说软件工程中软件编程必须有设计规格说明书,那么测试脚本的设计规格说明书就是测试用例。

    4、评估测试结果的度量基准

          完成测试实施后需要对测试结果进行评估,并且编制测试报告。判断软件测试是否完成、衡量测试质量需要一些量化的结果。例:测试覆盖率是多少、测试合格率是多少、重要测试合格率是多少,等等。以前统计基准是软件模块或功能点,显得过于粗糙。采用测试用例作度量基准更加准确、有效。

    5、分析缺陷的标准

          通过收集缺陷,对比测试用例和缺陷数据库,分析确证是漏测还是缺陷复现。漏测反映了测试用例的不完善,应立即补充相应测试用例,最终达到逐步完善软件质量。而已有相应测试用例,则反映实施测试或变更处理存在问题。

    五、相关问题

    1、测试用例的评审

          测试用例是软件测试的准则,但它并不是一经编制完成就成为准则。测试用例在设计编制过程中要组织同级互查。完成编制后应组织专家评审,需获得通过才可以使用。评审委员会可由项目负责人、测试、编程、分析设计等有关人员组成,也可邀请客户代表参加。

    2、测试用例的修改更新

          测试用例在形成文档后也还需要不断完善。主要来自三方面的缘故:第一、在测试过程中发现设计测试用例时考虑不周,需要完善;第二、在软件交付使用后反馈的软件缺陷,而缺陷又是因测试用例存在漏洞造成;第三、软件自身的新增功能以及软件版本的更新,测试用例也必须配套修改更新。

          一般小的修改完善可在原测试用例文档上修改,但文档要有更改记录。软件的版本升级更新,测试用例一般也应随之编制升级更新版本。

    3、测试用例的管理软件

          运用测试用例还需配备测试用例管理软件。它的主要功能有三个:第一、能将测试用例文档的关键内容,如编号、名称等等自动导入管理数据库,形成与测试用例文档完全对应的记录;第二、可供测试实施时及时输入测试情况;第三、最终实现自动生成测试结果文档,包含各测试度量值,测试覆盖表和测试通过或不通过的测试用例清单列表。

          有了管理软件,测试人员无论是编写每日的测试工作日志、还是出软件测试报告,都会变得轻而易举。

     

  • 测试方法概述

    2007-10-19 13:40:27

    测试方法概述

     

    1.         功能测试

    1.1.        手工测试与自动化工具测试划分

    分析软件系统的各个模块,

    将需要大量重复操作测试的功能做自动化测试

    将自动化测试实现较难的功能做手工测试

    1.2.        手工测试

    a           分析系统需求说明书和规格说明书,

    b           编写测试需求,

    c           根据测试需求书写测试用例

    d           按照测试用例,手动运行软件

    e           发现bug

    f            bug填写在vsts软件中

    g           通知开发人员修改程序

    h           进行回归测试

    1.3.        自动化测试

    a           分析系统需求说明书和规格说明书,

    b           编写测试需求,

    c           根据测试需求书写测试用例

    d           根据测试用例编写\录制测试脚本

    e           调试和整理测试脚本,

    f            运行测试脚本,进行测试。

    g           分析运行结果,发现bug

    h           bug填写在vsts软件中,

    i             通知开发人员修改程序

    j             进行回归测试

     

    1.4.        测试通过标准

    如果测试结果与预期结果一致测试通过,否则不通过。

     

    1.5.        测试结果审批过程

    测试工作执行完毕,写测试总结报告,召开测试总结会议,讨论产品是否可以发布(评审标准:测试案例是否完全,测试程序是否正确,测试结果是否令人满意,…)。

     

    1.6.        测试挂起和恢复条件

    l         测试挂起条件:

    由于程序中存在重大问题或者问题过多,测试无法正常进行,测试人员申请测试挂起,经领导审批通过;

    由于存在其他优先级更高的任务,通过批准,测试挂起。

    l         测试恢复条件:

    重大问题被解决或者程序通过重新修正;

    优先级更高的任务被完成。

     

    2.         性能测试

    2.1.        测试的要点

    速度 系统反应速度是否可以符合要求

    负载 测试系统是否可以在正常的负载范围内正常运行

    压力 测试系统的限制和故障恢复能力,是否会崩溃

    2.2.        具体实施方法

    预期指标的性能测试----测试系统要求的基本性能是否可以满足

    模拟多用户同一时间数据的上传和下发

    模拟多用户同一时间使用系统的相同功能

    模拟多用户同一时间使用系统的不同功能

    模拟多用户长时间适用系统,系统长时间运行(34天),测试系统的稳定性

    大量数据同时上传或下发,数据的传输是否有误

    网络性能测试测试,测试系统在网络延迟,网络断开,网络不稳定的状况下系统的运行情况以及是否可以有相应的措施

     

     

    3.         图形测试

    Ø         要确保图形有明确的用途,图片或动画不要胡乱地堆在一起,以免浪费传输时间。Web 应用系统的图片尺寸要尽量地小,并且要能清楚地说明某件事情,一般都链接到某个具体的页面。

    Ø         验证所有页面字体的风格是否一致。

    Ø          背景颜色应该与字体颜色和前景颜色相搭配。

    Ø          图片的大小和质量也是一个很重要的因素,一般采用JPG GIF 压缩。

    4.         内容测试

    内容测试用来检验应用系统提供信息的正确性、准确性和相关性

    5.         界面测试

    整体界面是指整个Web 应用系统的页面结构设计,是给用户的一个整体感。

    6.         操作系统版本测试

    检验在不同的操作系统版本下,系统的运行

    7.         安装与卸载测试

  • 全面介绍单元测试 -转贴

    2007-09-16 13:53:42

    这是一篇全面介绍单元测试的经典之作,对理解单元测试和Visual Unit很有帮助,作者老纳,收录时作了少量修改]

    一 单元测试概述
      工厂在组装一台电视机之前,会对每个元件都进行测试,这,就是单元测试。
      其实我们每天都在做单元测试。你写了一个函数,除了极简单的外,总是要执行一下,看看功能是否正常,有时还要想办法输出些数据,如弹出信息窗口什么 的,这,也是单元测试,老纳把这种单元测试称为临时单元测试。只进行了临时单元测试的软件,针对代码的测试很不完整,代码覆盖率要超过70%都很困难,未 覆盖的代码可能遗留大量的细小的错误,这些错误还会互相影响,当BUG暴露出来的时候难于调试,大幅度提高后期测试和维护成本,也降低了开发商的竞争力。 可以说,进行充分的单元测试,是提高软件质量,降低开发成本的必由之路。
      对于程序员来说,如果养成了对自己写的代码进行单元测试的习惯,不但可以写出高质量的代码,而且还能提高编程水平。
      要进行充分的单元测试,应专门编写测试代码,并与产品代码隔离。老纳认为,比较简单的办法是为产品工程建立对应的测试工程,为每个类建立对应的测试类,为每个函数(很简单的除外)建立测试函数。首先就几个概念谈谈老纳的看法。
      一般认为,在结构化程序时代,单元测试所说的单元是指函数,在当今的面向对象时代,单元测试所说的单元是指类。以老纳的实践来看,以类作为测试单位, 复杂度高,可操作性较差,因此仍然主张以函数作为单元测试的测试单位,但可以用一个测试类来组织某个类的所有测试函数。单元测试不应过分强调面向对象,因 为局部代码依然是结构化的。单元测试的工作量较大,简单实用高效才是硬道理。
      有一种看法是,只测试类的接口(公有函数),不测试其他函数,从面向对象角度来看,确实有其道理,但是,测试的目的是找错并最终排错,因此,只要是包 含错误的可能性较大的函数都要测试,跟函数是否私有没有关系。对于C++来说,可以用一种简单的方法区隔需测试的函数:简单的函数如数据读写函数的实现在 头文件中编写(inline函数),所有在源文件编写实现的函数都要进行测试(构造函数和析构函数除外)。
      什么时候测试?单元测试越早越好,早到什么程度?XP开发理论讲究TDD,即测试驱动开发,先编写测试代码,再进行开发。在实际的工作中,可以不必过 分强调先什么后什么,重要的是高效和感觉舒适。从老纳的经验来看,先编写产品函数的框架,然后编写测试函数,针对产品函数的功能编写测试用例,然后编写产 品函数的代码,每写一个功能点都运行测试,随时补充测试用例。所谓先编写产品函数的框架,是指先编写函数空的实现,有返回值的随便返回一个值,编译通过后 再编写测试代码,这时,函数名、参数表、返回类型都应该确定下来了,所编写的测试代码以后需修改的可能性比较小。
      由谁测试?单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。
      关于桩代码,老纳认为,单元测试应避免编写桩代码。桩代码就是用来代替某些代码的代码,例如,产品函数或测试函数调用了一个未编写的函数,可以编写桩 函数来代替该被调用的函数,桩代码也用于实现测试隔离。采用由底向上的方式进行开发,底层的代码先开发并先测试,可以避免编写桩代码,这样做的好处有:减 少了工作量;测试上层函数时,也是对下层函数的间接测试;当下层函数修改时,通过回归测试可以确认修改是否导致上层函数产生错误。

    二 测试代码编写
      多数讲述单元测试的文章都是以Java为例,本文以C++为例,后半部分所介绍的单元测试工具也只介绍C++单元测试工具。下面的示例代码的开发环境是VC6.0。

    产品类:
    class CMyClass
    {
    public:
        int Add(int i, int j);
        CMyClass();
        virtual ~CMyClass();

    private:
        int mAge;      //年龄
        CString mPhase; //年龄阶段,如"少年","青年"
    };

    建立对应的测试类CMyClassTester,为了节约编幅,只列出源文件的代码:
    void CMyClassTester::CaseBegin()
    {
        //pObj是CMyClassTester类的成员变量,是被测试类的对象的指针,
        //为求简单,所有的测试类都可以用pObj命名被测试对象的指针。
        pObj = new CMyClass();
    }

    void CMyClassTester::CaseEnd()
    {
        delete pObj;
    }
    测试类的函数CaseBegin()和CaseEnd()建立和销毁被测试对象,每个测试用例的开头都要调用CaseBegin(),结尾都要调用CaseEnd()。

    接下来,我们建立示例的产品函数:
    int CMyClass::Add(int i, int j)
    {
        return i+j;
    }
    和对应的测试函数:
    void CMyClassTester::Add_int_int()
    {
    }
    把参数表作为函数名的一部分,这样当出现重载的被测试函数时,测试函数不会产生命名冲突。下面添加测试用例:
    void CMyClassTester::Add_int_int()
    {
        //第一个测试用例
        CaseBegin();{              //1
        int i = 0;                //2
        int j = 0;                //3
        int ret = pObj->Add(i, j); //4
        ASSERT(ret == 0);          //5
        }CaseEnd();                //6
    }
    第1和第6行建立和销毁被测试对象,所加的{}是为了让每个测试用例的代码有一个独立的域,以便多个测试用例使用相同的变量名。
    第2和第3行是定义输入数据,第4行是调用被测试函数,这些容易理解,不作进一步解释。第5行是预期输出,它的特点是当实际输出与预期输出不同时自动报 错,ASSERT是VC的断言宏,也可以使用其他类似功能的宏,使用测试工具进行单元测试时,可以使用该工具定义的断言宏。

      示例中的格式显得很不简洁,2、3、4、5行可以合写为一行:ASSERT(pObj->Add(0, 0) == 0);但这种不简洁的格式却是老纳极力推荐的,因为它一目了然,易于建立多个测试用例,并且具有很好的适应性,同时,也是极佳的代码文档,总之,老纳建 议:输入数据和预期输出要自成一块。
      建立了第一个测试用例后,应编译并运行测试,以排除语法错误,然后,使用拷贝/修改的办法建立其他测试用例。由于各个测试用例之间的差别往往很小,通常只需修改一两个数据,拷贝/修改是建立多个测试用例的最快捷办法。

    三 测试用例
      下面说说测试用例、输入数据及预期输出。输入数据是测试用例的核心,老纳对输入数据的定义是:被测试函数所读取的外部数据及这些数据的初始值。外部数 据是对于被测试函数来说的,实际上就是除了局部变量以外的其他数据,老纳把这些数据分为几类:参数、成员变量、全局变量、IO媒体。IO媒体是指文件、数 据库或其他储存或传输数据的媒体,例如,被测试函数要从文件或数据库读取数据,那么,文件或数据库中的原始数据也属于输入数据。一个函数无论多复杂,都无 非是对这几类数据的读取、计算和写入。预期输出是指:返回值及被测试函数所写入的外部数据的结果值。返回值就不用说了,被测试函数进行了写操作的参数(输 出参数)、成员变量、全局变量、IO媒体,它们的预期的结果值都是预期输出。一个测试用例,就是设定输入数据,运行被测试函数,然后判断实际输出是否符合 预期。下面举一个与成员变量有关的例子:
    产品函数:
    void CMyClass::Grow(int years)
    {
        mAge += years;

        if(mAge < 10)
            mPhase = "儿童";
        else if(mAge <20)
            mPhase = "少年";
        else if(mAge <45)
            mPhase = "青年";
        else if(mAge <60)
            mPhase = "中年";
        else
            mPhase = "老年";
    }

    测试函数中的一个测试用例:
        CaseBegin();{
        int years = 1;
        pObj->mAge = 8;
        pObj->Grow(years);
        ASSERT( pObj->mAge == 9 );
        ASSERT( pObj->mPhase == "儿童" );
        }CaseEnd();
    在输入数据中对被测试类的成员变量mAge进行赋值,在预期输出中断言成员变量的值。现在可以看到老纳所推荐的格式的好处了吧,这种格式可以适应很复杂的 测试。在输入数据部分还可以调用其他成员函数,例如:执行被测试函数前可能需要读取文件中的数据保存到成员变量,或需要连接数据库,老纳把这些操作称为初 始化操作。例如,上例中 ASSERT( ...)之前可以加pObj->OpenFile();。为了访问私有成员,可以将测试类定义为产品类的友元类。例如,定义一个宏:
    #define UNIT_TEST(cls) friend class cls##Tester;
    然后在产品类声明中加一行代码:UNIT_TEST(ClassName)。

      下面谈谈测试用例设计。前面已经说了,测试用例的核心是输入数据。预期输出是依据输入数据和程序功能来确定的,也就是说,对于某一程序,输入数据确定 了,预期输出也就可以确定了,至于生成/销毁被测试对象和运行测试的语句,是所有测试用例都大同小异的,因此,我们讨论测试用例时,只讨论输入数据。
      前面说过,输入数据包括四类:参数、成员变量、全局变量、IO媒体,这四类数据中,只要所测试的程序需要执行读操作的,就要设定其初始值,其中,前两 类比较常用,后两类较少用。显然,把输入数据的所有可能取值都进行测试,是不可能也是无意义的,我们应该用一定的规则选择有代表性的数据作为输入数据,主 要有三种:正常输入,边界输入,非法输入,每种输入还可以分类,也就是平常说的等价类法,每类取一个数据作为输入数据,如果测试通过,可以肯定同类的其他 输入也是可以通过的。下面举例说明:
      正常输入
      例如字符串的Trim函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前面有空格;后面有空格;前后均有空格;前后均无空格。
      边界输入
      上例中空字符串可以看作是边界输入。
      再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:0和100。
      非法输入
      非法输入是正常取值范围以外的数据,或使代码不能完成正常功能的输入,如上例中表示年龄的参数,小于0或大于100都是非法输入,再如一个进行文件操作的函数,非法输入有这么几类:文件不存在;目录不存在;文件正在被其他程序打开;权限错误。
      如果函数使用了外部数据,则正常输入是肯定会有的,而边界输入和非法输入不是所有函数都有。一般情况下,即使没有设计文档,考虑以上三种输入也可以找 出函数的基本功能点。实际上,单元测试与代码编写是“一体两面”的关系,编码时对上述三种输入都是必须考虑的,否则代码的健壮性就会成问题。

    四 白盒覆盖
      上面所说的测试数据都是针对程序的功能来设计的,就是所谓的黑盒测试。单元测试还需要从另一个角度来设计测试数据,即针对程序的逻辑结构来设计测试用 例,就是所谓的白盒测试。在老纳看来,如果黑盒测试是足够充分的,那么白盒测试就没有必要,可惜“足够充分”只是一种理想状态,例如:真的是所有功能点都 测试了吗?程序的功能点是人为的定义,常常是不全面的;各个输入数据之间,有些组合可能会产生问题,怎样保证这些组合都经过了测试?难于衡量测试的完整性 是黑盒测试的主要缺陷,而白盒测试恰恰具有易于衡量测试完整性的优点,两者之间具有极好的互补性,例如:完成功能测试后统计语句覆盖率,如果语句覆盖未完 成,很可能是未覆盖的语句所对应的功能点未测试。
      白盒测试针对程序的逻辑结构设计测试用例,用逻辑覆盖率来衡量测试的完整性。逻辑单位主要有:语句、分支、条件、条件值、条件值组合,路径。语句覆盖 就是覆盖所有的语句,其他类推。另外还有一种判定条件覆盖,其实是分支覆盖与条件覆盖的组合,在此不作讨论。跟条件有关的覆盖就有三种,解释一下:条件覆 盖是指覆盖所有的条件表达式,即所有的条件表达式都至少计算一次,不考虑计算结果;条件值覆盖是指覆盖条件的所有可能取值,即每个条件的取真值和取假值都 要至少计算一次;条件值组合覆盖是指覆盖所有条件取值的所有可能组合。老纳做过一些粗浅的研究,发现与条件直接有关的错误主要是逻辑操作符错误,例如: ||写成&&,漏了写!什么的,采用分支覆盖与条件覆盖的组合,基本上可以发现这些错误,另一方面,条件值覆盖与条件值组合覆盖往往需要 大量的测试用例,因此,在老纳看来,条件值覆盖和条件值组合覆盖的效费比偏低。老纳认为效费比较高且完整性也足够的测试要求是这样的:完成功能测试,完成 语句覆盖、条件覆盖、分支覆盖、路径覆盖。做过单元测试的朋友恐怕会对老纳提出的测试要求给予一个字的评价:晕!或者两个字的评价:狂晕!因为这似乎是不 可能的要求,要达到这种测试完整性,其测试成本是不可想象的,不过,出家人不打逛语,老纳之所以提出这种测试要求,是因为利用一些工具,可以在较低的成本 下达到这种测试要求,后面将会作进一步介绍。
      关于白盒测试用例的设计,程序测试领域的书籍一般都有讲述,普通方法是画出程序的逻辑结构图如程序流程图或控制流图,根据逻辑结构图设计测试用例,这 些是纯粹的白盒测试,不是老纳想推荐的方式。老纳所推荐的方法是:先完成黑盒测试,然后统计白盒覆盖率,针对未覆盖的逻辑单位设计测试用例覆盖它,例如, 先检查是否有语句未覆盖,有的话设计测试用例覆盖它,然后用同样方法完成条件覆盖、分支覆盖和路径覆盖,这样的话,既检验了黑盒测试的完整性,又避免了重 复的工作,用较少的时间成本达到非常高的测试完整性。不过,这些工作可不是手工能完成的,必须借助于工具,后面会介绍可以完成这些工作的测试工具。

    五 单元测试工具
      现在开始介绍单元测试工具,老纳只介绍三种,都是用于C++语言的。
      首先是CppUnit,这是C++单元测试工具的鼻祖,免费的开源的单元测试框架。由于已有一众高人写了不少关于CppUnit的很好的文章,老纳就不现丑了,想了解CppUnit的朋友,建议读一下Cpluser 所作的《CppUnit测试框架入门》,网址是:http://blog.csdn.net/cpluser/archive/2004/09/21/111522.aspx。该文也提供了CppUnit的下载地址。
      然后介绍C++Test,这是Parasoft公司的产品。[C++Test是一个功能强大的自动化C/C++单元级测试工具,可以自动测试任何 C/C++函数、类,自动生成测试用例、测试驱动函数或桩函数,在自动化的环境下极其容易快速的将单元级的测试覆盖率达到100%]。[]内的文字引自http://www.superst.com.cn/softwares_testing_c_cpptest.htm, 这是华唐公司的网页。老纳想写些介绍C++Test的文字,但发现无法超越华唐公司的网页上的介绍,所以也就省点事了,想了解C++Test的朋友,建议 访问该公司的网站。华唐公司代理C++Test,想要购买或索取报价、试用版都可以找他们。老纳帮华唐公司做广告,不知道会不会得点什么好处?
      最后介绍Visual Unit,简称VU,这是国产的单元测试工具,据说申请了多项专利,拥有一批创新的技术,不过老纳只关心是不是有用和好用。[自动生成测试代码 快速建立功能测试用例 程序行为一目了然 极高的测试完整性 高效完成白盒覆盖 快速排错 高效调试 详尽的测试报告]。[]内的文字是VU开发商的网页上摘录的,网址是:http://www.unitware.cn。 前面所述测试要求:完成功能测试,完成语句覆盖、条件覆盖、分支覆盖、路径覆盖,用VU可以轻松实现,还有一点值得一提:使用VU还能提高编码的效率,总 体来说,在完成单元测试的同时,编码调试的时间还能大幅度缩短。算了,不想再讲了,老纳显摆理论、介绍经验还是有兴趣的,因为可以满足老纳好为人师的虚荣 心,但介绍工具就觉得索然无味了,毕竟工具好不好用,合不合用,要试过才知道,还是自己去开发商的网站看吧,可以下载演示版,还有演示课件。
    这是一篇全面介绍单元测试的经典之作,对理解单元测试和Visual Unit很有帮助,作者老纳,收录时作了少量修改]

    一 单元测试概述
      工厂在组装一台电视机之前,会对每个元件都进行测试,这,就是单元测试。
      其实我们每天都在做单元测试。你写了一个函数,除了极简单的外,总是要执行一下,看看功能是否正常,有时还要想办法输出些数据,如弹出信息窗口什么 的,这,也是单元测试,老纳把这种单元测试称为临时单元测试。只进行了临时单元测试的软件,针对代码的测试很不完整,代码覆盖率要超过70%都很困难,未 覆盖的代码可能遗留大量的细小的错误,这些错误还会互相影响,当BUG暴露出来的时候难于调试,大幅度提高后期测试和维护成本,也降低了开发商的竞争力。 可以说,进行充分的单元测试,是提高软件质量,降低开发成本的必由之路。
      对于程序员来说,如果养成了对自己写的代码进行单元测试的习惯,不但可以写出高质量的代码,而且还能提高编程水平。
      要进行充分的单元测试,应专门编写测试代码,并与产品代码隔离。老纳认为,比较简单的办法是为产品工程建立对应的测试工程,为每个类建立对应的测试类,为每个函数(很简单的除外)建立测试函数。首先就几个概念谈谈老纳的看法。
      一般认为,在结构化程序时代,单元测试所说的单元是指函数,在当今的面向对象时代,单元测试所说的单元是指类。以老纳的实践来看,以类作为测试单位, 复杂度高,可操作性较差,因此仍然主张以函数作为单元测试的测试单位,但可以用一个测试类来组织某个类的所有测试函数。单元测试不应过分强调面向对象,因 为局部代码依然是结构化的。单元测试的工作量较大,简单实用高效才是硬道理。
      有一种看法是,只测试类的接口(公有函数),不测试其他函数,从面向对象角度来看,确实有其道理,但是,测试的目的是找错并最终排错,因此,只要是包 含错误的可能性较大的函数都要测试,跟函数是否私有没有关系。对于C++来说,可以用一种简单的方法区隔需测试的函数:简单的函数如数据读写函数的实现在 头文件中编写(inline函数),所有在源文件编写实现的函数都要进行测试(构造函数和析构函数除外)。
      什么时候测试?单元测试越早越好,早到什么程度?XP开发理论讲究TDD,即测试驱动开发,先编写测试代码,再进行开发。在实际的工作中,可以不必过 分强调先什么后什么,重要的是高效和感觉舒适。从老纳的经验来看,先编写产品函数的框架,然后编写测试函数,针对产品函数的功能编写测试用例,然后编写产 品函数的代码,每写一个功能点都运行测试,随时补充测试用例。所谓先编写产品函数的框架,是指先编写函数空的实现,有返回值的随便返回一个值,编译通过后 再编写测试代码,这时,函数名、参数表、返回类型都应该确定下来了,所编写的测试代码以后需修改的可能性比较小。
      由谁测试?单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。
      关于桩代码,老纳认为,单元测试应避免编写桩代码。桩代码就是用来代替某些代码的代码,例如,产品函数或测试函数调用了一个未编写的函数,可以编写桩 函数来代替该被调用的函数,桩代码也用于实现测试隔离。采用由底向上的方式进行开发,底层的代码先开发并先测试,可以避免编写桩代码,这样做的好处有:减 少了工作量;测试上层函数时,也是对下层函数的间接测试;当下层函数修改时,通过回归测试可以确认修改是否导致上层函数产生错误。

    二 测试代码编写
      多数讲述单元测试的文章都是以Java为例,本文以C++为例,后半部分所介绍的单元测试工具也只介绍C++单元测试工具。下面的示例代码的开发环境是VC6.0。

    产品类:
    class CMyClass
    {
    public:
        int Add(int i, int j);
        CMyClass();
        virtual ~CMyClass();

    private:
        int mAge;      //年龄
        CString mPhase; //年龄阶段,如"少年","青年"
    };

    建立对应的测试类CMyClassTester,为了节约编幅,只列出源文件的代码:
    void CMyClassTester::CaseBegin()
    {
        //pObj是CMyClassTester类的成员变量,是被测试类的对象的指针,
        //为求简单,所有的测试类都可以用pObj命名被测试对象的指针。
        pObj = new CMyClass();
    }

    void CMyClassTester::CaseEnd()
    {
        delete pObj;
    }
    测试类的函数CaseBegin()和CaseEnd()建立和销毁被测试对象,每个测试用例的开头都要调用CaseBegin(),结尾都要调用CaseEnd()。

    接下来,我们建立示例的产品函数:
    int CMyClass::Add(int i, int j)
    {
        return i+j;
    }
    和对应的测试函数:
    void CMyClassTester::Add_int_int()
    {
    }
    把参数表作为函数名的一部分,这样当出现重载的被测试函数时,测试函数不会产生命名冲突。下面添加测试用例:
    void CMyClassTester::Add_int_int()
    {
        //第一个测试用例
        CaseBegin();{              //1
        int i = 0;                //2
        int j = 0;                //3
        int ret = pObj->Add(i, j); //4
        ASSERT(ret == 0);          //5
        }CaseEnd();                //6
    }
    第1和第6行建立和销毁被测试对象,所加的{}是为了让每个测试用例的代码有一个独立的域,以便多个测试用例使用相同的变量名。
    第2和第3行是定义输入数据,第4行是调用被测试函数,这些容易理解,不作进一步解释。第5行是预期输出,它的特点是当实际输出与预期输出不同时自动报 错,ASSERT是VC的断言宏,也可以使用其他类似功能的宏,使用测试工具进行单元测试时,可以使用该工具定义的断言宏。

      示例中的格式显得很不简洁,2、3、4、5行可以合写为一行:ASSERT(pObj->Add(0, 0) == 0);但这种不简洁的格式却是老纳极力推荐的,因为它一目了然,易于建立多个测试用例,并且具有很好的适应性,同时,也是极佳的代码文档,总之,老纳建 议:输入数据和预期输出要自成一块。
      建立了第一个测试用例后,应编译并运行测试,以排除语法错误,然后,使用拷贝/修改的办法建立其他测试用例。由于各个测试用例之间的差别往往很小,通常只需修改一两个数据,拷贝/修改是建立多个测试用例的最快捷办法。

    三 测试用例
      下面说说测试用例、输入数据及预期输出。输入数据是测试用例的核心,老纳对输入数据的定义是:被测试函数所读取的外部数据及这些数据的初始值。外部数 据是对于被测试函数来说的,实际上就是除了局部变量以外的其他数据,老纳把这些数据分为几类:参数、成员变量、全局变量、IO媒体。IO媒体是指文件、数 据库或其他储存或传输数据的媒体,例如,被测试函数要从文件或数据库读取数据,那么,文件或数据库中的原始数据也属于输入数据。一个函数无论多复杂,都无 非是对这几类数据的读取、计算和写入。预期输出是指:返回值及被测试函数所写入的外部数据的结果值。返回值就不用说了,被测试函数进行了写操作的参数(输 出参数)、成员变量、全局变量、IO媒体,它们的预期的结果值都是预期输出。一个测试用例,就是设定输入数据,运行被测试函数,然后判断实际输出是否符合 预期。下面举一个与成员变量有关的例子:
    产品函数:
    void CMyClass::Grow(int years)
    {
        mAge += years;

        if(mAge < 10)
            mPhase = "儿童";
        else if(mAge <20)
            mPhase = "少年";
        else if(mAge <45)
            mPhase = "青年";
        else if(mAge <60)
            mPhase = "中年";
        else
            mPhase = "老年";
    }

    测试函数中的一个测试用例:
        CaseBegin();{
        int years = 1;
        pObj->mAge = 8;
        pObj->Grow(years);
        ASSERT( pObj->mAge == 9 );
        ASSERT( pObj->mPhase == "儿童" );
        }CaseEnd();
    在输入数据中对被测试类的成员变量mAge进行赋值,在预期输出中断言成员变量的值。现在可以看到老纳所推荐的格式的好处了吧,这种格式可以适应很复杂的 测试。在输入数据部分还可以调用其他成员函数,例如:执行被测试函数前可能需要读取文件中的数据保存到成员变量,或需要连接数据库,老纳把这些操作称为初 始化操作。例如,上例中 ASSERT( ...)之前可以加pObj->OpenFile();。为了访问私有成员,可以将测试类定义为产品类的友元类。例如,定义一个宏:
    #define UNIT_TEST(cls) friend class cls##Tester;
    然后在产品类声明中加一行代码:UNIT_TEST(ClassName)。

      下面谈谈测试用例设计。前面已经说了,测试用例的核心是输入数据。预期输出是依据输入数据和程序功能来确定的,也就是说,对于某一程序,输入数据确定 了,预期输出也就可以确定了,至于生成/销毁被测试对象和运行测试的语句,是所有测试用例都大同小异的,因此,我们讨论测试用例时,只讨论输入数据。
      前面说过,输入数据包括四类:参数、成员变量、全局变量、IO媒体,这四类数据中,只要所测试的程序需要执行读操作的,就要设定其初始值,其中,前两 类比较常用,后两类较少用。显然,把输入数据的所有可能取值都进行测试,是不可能也是无意义的,我们应该用一定的规则选择有代表性的数据作为输入数据,主 要有三种:正常输入,边界输入,非法输入,每种输入还可以分类,也就是平常说的等价类法,每类取一个数据作为输入数据,如果测试通过,可以肯定同类的其他 输入也是可以通过的。下面举例说明:
      正常输入
      例如字符串的Trim函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前面有空格;后面有空格;前后均有空格;前后均无空格。
      边界输入
      上例中空字符串可以看作是边界输入。
      再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:0和100。
      非法输入
      非法输入是正常取值范围以外的数据,或使代码不能完成正常功能的输入,如上例中表示年龄的参数,小于0或大于100都是非法输入,再如一个进行文件操作的函数,非法输入有这么几类:文件不存在;目录不存在;文件正在被其他程序打开;权限错误。
      如果函数使用了外部数据,则正常输入是肯定会有的,而边界输入和非法输入不是所有函数都有。一般情况下,即使没有设计文档,考虑以上三种输入也可以找 出函数的基本功能点。实际上,单元测试与代码编写是“一体两面”的关系,编码时对上述三种输入都是必须考虑的,否则代码的健壮性就会成问题。

    四 白盒覆盖
      上面所说的测试数据都是针对程序的功能来设计的,就是所谓的黑盒测试。单元测试还需要从另一个角度来设计测试数据,即针对程序的逻辑结构来设计测试用 例,就是所谓的白盒测试。在老纳看来,如果黑盒测试是足够充分的,那么白盒测试就没有必要,可惜“足够充分”只是一种理想状态,例如:真的是所有功能点都 测试了吗?程序的功能点是人为的定义,常常是不全面的;各个输入数据之间,有些组合可能会产生问题,怎样保证这些组合都经过了测试?难于衡量测试的完整性 是黑盒测试的主要缺陷,而白盒测试恰恰具有易于衡量测试完整性的优点,两者之间具有极好的互补性,例如:完成功能测试后统计语句覆盖率,如果语句覆盖未完 成,很可能是未覆盖的语句所对应的功能点未测试。
      白盒测试针对程序的逻辑结构设计测试用例,用逻辑覆盖率来衡量测试的完整性。逻辑单位主要有:语句、分支、条件、条件值、条件值组合,路径。语句覆盖 就是覆盖所有的语句,其他类推。另外还有一种判定条件覆盖,其实是分支覆盖与条件覆盖的组合,在此不作讨论。跟条件有关的覆盖就有三种,解释一下:条件覆 盖是指覆盖所有的条件表达式,即所有的条件表达式都至少计算一次,不考虑计算结果;条件值覆盖是指覆盖条件的所有可能取值,即每个条件的取真值和取假值都 要至少计算一次;条件值组合覆盖是指覆盖所有条件取值的所有可能组合。老纳做过一些粗浅的研究,发现与条件直接有关的错误主要是逻辑操作符错误,例如: ||写成&&,漏了写!什么的,采用分支覆盖与条件覆盖的组合,基本上可以发现这些错误,另一方面,条件值覆盖与条件值组合覆盖往往需要 大量的测试用例,因此,在老纳看来,条件值覆盖和条件值组合覆盖的效费比偏低。老纳认为效费比较高且完整性也足够的测试要求是这样的:完成功能测试,完成 语句覆盖、条件覆盖、分支覆盖、路径覆盖。做过单元测试的朋友恐怕会对老纳提出的测试要求给予一个字的评价:晕!或者两个字的评价:狂晕!因为这似乎是不 可能的要求,要达到这种测试完整性,其测试成本是不可想象的,不过,出家人不打逛语,老纳之所以提出这种测试要求,是因为利用一些工具,可以在较低的成本 下达到这种测试要求,后面将会作进一步介绍。
      关于白盒测试用例的设计,程序测试领域的书籍一般都有讲述,普通方法是画出程序的逻辑结构图如程序流程图或控制流图,根据逻辑结构图设计测试用例,这 些是纯粹的白盒测试,不是老纳想推荐的方式。老纳所推荐的方法是:先完成黑盒测试,然后统计白盒覆盖率,针对未覆盖的逻辑单位设计测试用例覆盖它,例如, 先检查是否有语句未覆盖,有的话设计测试用例覆盖它,然后用同样方法完成条件覆盖、分支覆盖和路径覆盖,这样的话,既检验了黑盒测试的完整性,又避免了重 复的工作,用较少的时间成本达到非常高的测试完整性。不过,这些工作可不是手工能完成的,必须借助于工具,后面会介绍可以完成这些工作的测试工具。

    五 单元测试工具
      现在开始介绍单元测试工具,老纳只介绍三种,都是用于C++语言的。
      首先是CppUnit,这是C++单元测试工具的鼻祖,免费的开源的单元测试框架。由于已有一众高人写了不少关于CppUnit的很好的文章,老纳就不现丑了,想了解CppUnit的朋友,建议读一下Cpluser 所作的《CppUnit测试框架入门》,网址是:http://blog.csdn.net/cpluser/archive/2004/09/21/111522.aspx。该文也提供了CppUnit的下载地址。
      然后介绍C++Test,这是Parasoft公司的产品。[C++Test是一个功能强大的自动化C/C++单元级测试工具,可以自动测试任何 C/C++函数、类,自动生成测试用例、测试驱动函数或桩函数,在自动化的环境下极其容易快速的将单元级的测试覆盖率达到100%]。[]内的文字引自http://www.superst.com.cn/softwares_testing_c_cpptest.htm, 这是华唐公司的网页。老纳想写些介绍C++Test的文字,但发现无法超越华唐公司的网页上的介绍,所以也就省点事了,想了解C++Test的朋友,建议 访问该公司的网站。华唐公司代理C++Test,想要购买或索取报价、试用版都可以找他们。老纳帮华唐公司做广告,不知道会不会得点什么好处?
      最后介绍Visual Unit,简称VU,这是国产的单元测试工具,据说申请了多项专利,拥有一批创新的技术,不过老纳只关心是不是有用和好用。[自动生成测试代码 快速建立功能测试用例 程序行为一目了然 极高的测试完整性 高效完成白盒覆盖 快速排错 高效调试 详尽的测试报告]。[]内的文字是VU开发商的网页上摘录的,网址是:http://www.unitware.cn。 前面所述测试要求:完成功能测试,完成语句覆盖、条件覆盖、分支覆盖、路径覆盖,用VU可以轻松实现,还有一点值得一提:使用VU还能提高编码的效率,总 体来说,在完成单元测试的同时,编码调试的时间还能大幅度缩短。算了,不想再讲了,老纳显摆理论、介绍经验还是有兴趣的,因为可以满足老纳好为人师的虚荣 心,但介绍工具就觉得索然无味了,毕竟工具好不好用,合不合用,要试过才知道,还是自己去开发商的网站看吧,可以下载演示版,还有演示课件。




    文中提到的Visual Unit,现在有免费版本了
    Visual Unit 简介
    Visual Unit(VU) 解决了实施单元测试面临的主要问题:单元测试降低编码阶段的生产效率? VU自动生成测试代码,全方位示出程序行为,帮助整理和验证编码思路,支持快速排错和高效调试,边编码边测试反而可以提高编码的生产率;开发人员不喜欢测 试自已编写的代码? VU使程序的功能和逻辑结构一目了然,既是测试工具,也是编码辅助工具,提高了编程的舒适度,容易让开发人员接受和喜爱;单元测试的效果难于保证、难于持 续实施,并行开发难于保证覆盖率? VU可轻松完成100%语句、条件、分支、路径覆盖,提供详尽的测试报告和待测试文件列表,随时可以检验测试效果、找出遗漏代码或未完成覆盖的代码,保证 测试的完整性,易于持续实施。
    Visual Unit目前的版本支持VC6.0,VC.Net,C++Builder 6.0。
    Visual Unit的发布版本包括企业版和个人版,其中,个人版是完全免费的版本

    下载安装
    可从官方网站下载Visual Unit 1.1,网址为http://www.UnitWare.cn。安装包只有5.67M,但已包含了个人版和企业版。安装后,个人版即可免费使用,企业版在经过简单的注册后,可以免费试用一段时间。

    开始使用Visual Unit
    下面是VU的入门操作,根据帮助系统中的《VU入门指引》修改而成,实际使用时建议直接阅读该指引,VU第一次启动时会询问是否浏览该指引。

    1. 打开示例工程或新建测试工程
    打开示例工程:
    启动您的开发环境(如VC6.0),打开示例的测试工程,目录为:@ROOT@\Samples\@IDE@\TestDemo\
    将以下目录添加到开发环境的搜索路径:@ROOT@\include\ 及 @ROOT@\Samples\@IDE@\Demo\
    @ROOT@表示VU的安装目录,如C:\Program Files\Visual Unit。
    @IDE@表示开发环境的名称,目前有四种:VC 6.0、VC .Net、VC.Net 2003、C++ Builder。
    测试用例编辑器中可以阅读每一个示例的说明,该说明位于测试用例摘要下方。初学者最好看一下帮助系统中《关于示例的说明》。

    或新建测试工程:
    不同的开发环境建立和配置测试工程的操作稍有不同,请按照帮助系统的说明进行。
    如果IDE是C++ Builder,测试时要在IDE中打开测试工程根目录下的VuxCodeImp.h文件,请阅读帮助系统《关于C++Builder的特殊事项》。

    2. 选择要测试的产品文件和要测试的函数,自动生成测试文件和测试函数
    在导航窗口中选择一个产品文件,如果测试文件不存在会弹出提示,生成测试文件;
    在导航窗口的函数列表中选择一个函数,如果测试函数不存在会弹出提示,生成测试函数,并自动弹出测试用例编辑器。

    3. 填写测试用例
    在测试用例编辑器中“输入数据”和“预期输出”输入框中填写测试用例的输入和预期的输出。点击“新建”按钮将复制当前测试用例,修改输入和输出即可获得新的测试用例。

    4. 运行测试
    用您的开发环境编译并运行测试工程,即可执行测试。测试完毕,主窗口自动弹出,显示测试结果。

    示例工程的主要文件是由VC6.0开发的,其他IDE在编译时会产生一些编译警告,可以忽略这些编译警告,有些代码会产生异常,缺省设置是不作处理,可以 设为捕获异常(导航窗口菜单->选项->扩展,在“捕获异常”复选框前打勾),对于企业版,建议不要捕获异常,程序崩溃时不要即时调试(出现 崩溃窗口时应选择“确定”),观察数据窗口和代码窗口通常可以快速地发现出错位置和出错原因。

    5. 使用IDE插件
    目前版本已经开发了VC6.0插件,使用该插件,点击一个按钮,即可完成步骤2. 3. 4的操作。该插件的安装和使用请查阅帮助系统。[个人版不支持IDE插件]

  • 单元测试------理论篇

    2007-09-16 13:51:40

    单元测试------理论篇(转)
    测试是软件开发的重要环节之一。按照软件开发的过程测试可分为:单元测试、集成测试、系统测试、域测试(Field test)等。我们这里将讨论面向程序员的单元测试。本文首先介绍单元测试的定义,为什么要使用单元测试?单元测试能给我们带来的好处。之后我们将介绍单 元测试的范畴,最后将讨论很多朋友不写单元测试的借口。希望本文能够再次引起您对单元测试的重视,并说服您老板对编写单元测试的支持,能让美丽的单元测试 真正应用到您的项目之中。

    什么是单元测试
          单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景) 下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。
        单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。

    为什么要使用单元测试
        我们编写代码时,一定会反复调试保证它能够编译通过。如果是编译没有通过的代码,没有任何人会愿意交付给自己的老板。但代码通过编译,只是说明了它的语法正确;我们却无法保证它的语义也一定正确,没有任何人可以轻易承诺这段代码的行为一定是正确的。
        幸运,单元测试会为我们的承诺做保证。编写单元测试就是用来验证这段代码的行为是否与我们期望的一致。有了单元测试,我们可以自信的交付自己的代码,而没有任何的后顾之忧。

    单元测试有下面的这些优点:
    1、它是一种验证行为。
        程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支缓。就算是开发后期,我们也可以轻松的增加功能或更改程序结构,而不用担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样,我们就可以更自由的对程序进行改进。
    2、它是一种设计行为。
        编写单元测试将使我们从调用者观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。
    3、它是一种编写文档的行为。
        单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。
    4、它具有回归性。
        自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。

    单元测试的范畴
        如果要给单元测试定义一个明确的范畴,指出哪些功能是属于单元测试,这似乎很难。但下面讨论的四个问题,基本上可以说明单元测试的范畴,单元测试所要做的工作。
    1、 它的行为和我期望的一致吗?
        这是单元测试最根本的目的,我们就是用单元测试的代码来证明它所做的就是我们所期望的。
    2、 它的行为一直和我期望的一致吗?
        编写单元测试,如果只测试代码的一条正确路径,让它正确走一遍,并不算是真正的完成。软件开发是一个项复杂的工程,在测试某段代码的行为是否和你的期望一 致时,你需要确认:在任何情况下,这段代码是否都和你的期望一致;譬如参数很可疑、硬盘没有剩余空间、缓冲区溢出、网络掉线的时候。
    3、 我可以依赖单元测试吗?
       不能依赖的代码是没有多大用处的。既然单元测试是用来保证代码的正确性,那么单元测试也一定要值得依赖。
    4、 单元测试说明我的意图了吗?
        单元测试能够帮我们充分了解代码的用法,从效果上而言,单元测试就像是能执行的文档,说明了在你用各种条件调用代码时,你所能期望这段代码完成的功能。

    不写测试的借口
        到这里,我们已经列举了使用单元测试的种种理由。也许,每个人都同意,是的,该做更多的测试。这种人人同意的事情还多着呢,是的,该多吃蔬菜,该戒烟,该多休息,该多锻炼……这并不意味着我们中的所有人都会这么去做,不是吗?
    1、 编写单元测试太花时间了。
        我们知道,在开发时越早发现BUG,就能节省更多的时间,降低更多的风险。
        下图表摘自<<实用软件度量>>(Capers Jones,McGraw-Hill 1991),它列出了准备测试,执行测试,和修改缺陷所花费的时间(以一个功能点为基准),这些数据显示单元测试的成本效率大约是集成测试的两倍,是系统 测试的三倍(参见条形图)。

        术语:域测试(Field test)意思是在软件投入使用以后,针对某个领域所作的所有测试活动。
        如果你仍然认为在编写产品代码的时候,还是没有时间编写测试代码,那么请先考虑下面这些问题:
            1)、对于所编写的代码,你在调试上面花了多少时间。
            2)、对于以前你自认为正确的代码,而实际上这些代码却存在重大的bug,你花了多少时间在重新确认这些代码上面。
            3)、对于一个别人报告的bug,你花了多少时间才找出导致这个bug 的源码位置。
        回答完这些问题,你一定不再以“太花时间”作为拒绝单元测试的借口。
    2、 运行测试的时间太长了。
        合适的测试是不会让这种情况发生的。实际上,大多数测试的执行都是非常快的,因此你在几秒之内就可以运行成千上万个测试。但是有时某些测试会花费很长的时间。这时,需要把这些耗时的测试和其他测试分开。通常可以每天运行这种测试一次,或者几天一次。
    3、 测试代码并不是我的工作。
        你的工作就是保证代码能够正确的完成你的行为,恰恰相反,测试代码正是你不可缺少的工作。
    4、 我并不清楚代码的行为,所以也就无从测试。
       如果你实在不清楚代码的行为,那么估计现在并不是编码的时候。如果你并不知道代码的行为,那么你又如何知道你编写的代码是正确的呢?
    5、 但是这些代码都能够编译通过。
        我们前面已经说过,代码通过编译只是验证它的语法通过。但并不能保证它的行为就一定正确。
    6、 公司请我来是为了写代码,而不是写测试。
        公司付给你薪水是为了让你编写产品代码,而单元测试大体上是一个工具,是一个和编辑器、开发环境、编译器等处于同一位置的工具。
    7、 如果我让测试员或者QA(Quality Assurance)人员没有工作,那么我会觉得很内疚。
       你并不需要担心这些。请记住,我们在此只是谈论单元测试,而它只是一种针对源码的、低层次的,为程序员而设计的测试。在整个项目中,还有其他的很多测试需要这些人来完成,如:功能测试、验收测试、性能测试、环境测试、有效性测试、正确性测试、正规分析等等。
    8、 我的公司并不会让我在真实系统中运行单元测试。
        我们所讨论的只是针对开发者的单元测试。也就是说,如果你可以在其他的环境下(例如在正式的产品系统中)运行这些测试的话,那么它们就不再是单元测试,而是其他类型的测试了。实际上,你可以在你的本机运行单元测试,使用你自己的数据库,或者使用mock 对象。

    总结
      总而言之,单元测试会让我们的开发工作变得更加轻松,让我们对自己的代码更加自信。无论是大型项目还是小型项目,无论是时间紧迫的项目还是时间宽裕的项目,只要代码不是一次写完永不改动,编写单元测试就一定超值,它已成为我们编码不可缺少的一部分。
  • Java程序的单元测试

    2007-09-16 13:50:23

    Java程序的单元测试[分享]
    [本文原发测试时代,于此再发,望有利于各位]
    1.        单元测试的目的
    一个单元测试从整个系统中单独检验产品程序代码的『一个单元』并检查其得到的结果是否是预期的。要测试的『一个单元』其大小是依据一组连贯的功能的大小及 介于一个类别及一个包(package)之间实际上的变化(varies)。其目的是在整合程序代码到系统的其余部分之前先测试以便找出程序代码中的臭虫 (bugs)。Junit等支持在Java程序代码中撰写单元测试。
    在整合之前于系统其它部分隔离起来抓虫的理由是因为那是比较容易的找到臭虫(亦即比较快且便宜)及比较容易修正问题(并显示其解决方式是可行的)。
    单元测试对于在初始整合一小部分程序代码以及整合其余的改变之前提供了一些利益。如果有人需要变动现有的程序代码,事实上单元测试仍然可以让他对于其最后 的程序代码更有信心;即他的改变不会破坏任何东西。愈好的单元测试让人愈有信心--理想上测试必须在加入的新功能前也随之更新。
    2.        谁来撰写单元测试及何时撰写单元测试
    程序代码测试可能是非常乏味的,尤其是测试别人的程序,而当你是一个程序设计师的时候尤甚。但程序设计师喜欢撰写程序,因此为什么不让程序设计师撰写一些程序可以作为测试之用呢?
    当单元测试正确的实作可以帮助程序设计师变的更有生产力,而同时提升开发程序代码的品质。有一点你必须了解的是单元测试应该是开发程序的一部份是很重要 的;而且程序代码的设计必须是可以测试的。目前的趋势是在撰写程序代码之前要先撰写单元测试,并且把焦点放在Java类别的接口及行为上。
    先写测试,再写代码的好处:
    从技术上强制设计师先考虑一个类的功能,也就是这个类提供给外部的接口,而不至于太早陷入它的细节。这是面向对象提倡的一种设计原则。
    好的测试其实就是一个好的文档,这个类使用者往往可以通过查看这个类的测试代码了解它的功能。特别的,如果你拿到别人的一个程序,对他写测试是最好的了解 这个程序的功能的方法。 xp的原则是 make it simple,不是很推荐另外写文档,因为项目在开发过程中往往处于变动中,如果在早期写文档,以后代码变动后还得同步文档,多了一个工作,而且由于项目 时间紧往往文档写的不全或与代码不一致,与其这样,不如不写。而如果在项目结束后再写文档,开发人员往往已经忘记当时写代码时的种种考虑,况且有下一个项 目的压力,管理人员也不愿意再为旧的项目写文档。导致以后维护的问题
    没有人能保证需求不变动,以往项目往往对需求的变动大为头疼,害怕这个改动会带来其它地方的错误。为此,除了设计好的结构以分割项目外(松耦合),但如果 有了测试,并已经建立了一个好的测试框架,对于需求的变动,修改完代码后,只要重新运行测试代码,如果测试通过,也就保证了修改的成功,如果测试中出现错 误,也会马上发现错在哪里。修改相应的部分,再运行测试,直至测试完全通过。
    软件公司里往往存在开发部门和测试部门之间的矛盾:由于开发和测试分为两个部门,多了一层沟通的成本和时间,沟通往往会产生错误的发生。而且极易形成一个 怪圈:开发人员为了赶任务,写了烂烂的代码,就把它扔给测试人员,然后写其它的任务,测试当然是失败的,又把代码拿回去重写,测试就成了一个很头疼的问 题。这种怪圈的根源是责任不清,根据 xp 中的规定:写这个代码的人必须为自己的代码写测试,而且只有测试通过,才算完成这个任务(这里的测试包括所有的测试,如果测试时发现由于你的程序导致别的 组的测试失败,你有责任通知相关人员修改直至集成测试通过),这样就可以避免这类问题的发生。
    简而言之,如果程序设计师要写一段代码:
    先用 junit 写测试,然后再写代码;
    写完代码,运行测试,如果测试失败,
    修改代码,运行测试,直到测试成功。
    如果以后对程序进行修改,优化 ( refactoring ),只要再运行测试代码。如果所有的测试都成功,则代码修改完成。
    3.        单元测试与Java Team开发的结合
    Java下的team开发,一般采用cvs(版本控制) + ant(项目管理) + junit(单元测试、集成测试)的模式:
    每天早上上班,每个开发人员从 cvs server 获取一个整个项目的工作拷贝。
    拿到自己的任务,先用 junit 写今天的任务的测试代码。
    然后写今天任务的代码,运行测试(单元测试),直到测试通过。
    任务完成在下班前一两个小时,各个开发人员把任务提交到cvs server。
    然后由主管对整个项目运行自动测试(集成测试),哪个测试出错,就找相关人员修改,直到所有测试通过。下班。。。
    4.        测试控制工具中要有甚么?
    无论谁来撰写单元测试或何时撰写单元测试,我们的焦点应该放在检验程序代码;主要是在于产生错误的风险。如果设计文件包含被测试对象的使用情节;便可成为 好的测试来源。不管如何,这些情节写得不是很明确;因为这些情节实际上是以设计观点所写的--因此适当的测试应该有对等的情节,换句话说,也就是测试设计 应该尽可能的包含用户实际使用程序时可能产生的动作或者过程。
    另一个测试案例好的来源是在整合后从产品程序代码当中找到的问题,维修问题的处理方式往往值得封装成为测试案例。
    5.        为什么要使用Junit等工具呢?
    前面的论述说明为什么我们需要测试控制工具,但为什么我们使用Junit这些工具呢?
    首先,它们是完全Free的啦!。
    第二点,使用方便。
            在你提升程序代码的品质时JUnit测试仍允许你更快速的撰写程序
    那听起来似乎不是很直觉,但那是事实。当你使用JUnit撰写测试,你将花更少的时间除虫,同时对你程序代码的改变更 俱有信心。这个信心让你更积极重整程序代码并增加新的功能。没有测试,对于重整及增加新功能你会变得没有信心;因为你不知道有甚么东西会破坏产出的结果。 采用一个综合的测试系列,你可以在改变程序代码之后快速的执行多个测试并对于你的变动并未破坏任何东西感到有信心。在执行测试时如果发现臭虫,原始码仍然 清楚的在你脑中,因此很容易找到臭虫。在JUnit中撰写的测试帮助你以一种极 大(extreme)的步伐撰写程序及快速的找出缺点。
            JUnit非常简单
    撰写测试应该很简单--这是重点!如果撰写测试太复杂或太耗时间,便无法要求程序设计师撰写测试。使用JUnit你可以快速的撰写测试并检测你的程序代码 并逐 步随着程序代码的成长增加测试。只要你写了一些测试,你想要快速并频繁的执行测试而不至于中断建立设计及开发程序。使用JUnit执行测试就像编译你的程 序代码那么容易。事实上,你应该执行编译时也执行测试。编译是检测程序代码的语法而测试是检查程序代码的完整性(integrity)。
            JUnit测试检验其结果并提供立即的回馈。
    如果你是以人工比对测试的期望与实际结果那么测试是很不好玩的,而且让你的速度慢下来。JUnit测试可以自动执行并且检查他们自己的结果。当你执行测试,你获得简单且立即的回馈; 比如测试是通过或失败。而不再需要人工检查测试结果的报告。
            JUnit测试可以合成一个测试系列的层级架构。
    JUnit可以把测试组织成测试系列;这个测试系列可以包含其它的测试或测试系列。JUnit测试的合成行为允许你组合多个测试并自动的回归(regression)从头到尾测试整个测试系列。你也可以执行测试系列层级架构中任何一层的测试。
            撰写JUnit测试所费不多。
    使用Junit测试框架,你可以很便宜的撰写测试并享受由测试框架所提供的信心。撰写一个测试就像写一个方法一样简单;测试是检验要测试的程序代码并定义 期望的结果。这个测试框架提供自动执行测试的背景;这个背景并成为其它测试集合的一部份。在测试少量的投资将持续让你从时间及品质中获得回收。
            JUnit测试提升软件的稳定性。
    你写的测试愈少;你的程序代码变的愈不稳定。测试使得软件稳定并逐步累积信心;因为任何变动不会造成涟漪效应而漫及整个软件。测试可以形成软件的完整结构的胶结。
            JUnit测试是开发者测试。
    JUnit测试是高度区域性(localized)测试;用以改善开发者的生产力及程序代码品质。不像功能测试(function test)视系统为一个黑箱以确认软件整体的工作性为主,单元测试是由内而外测试系统基础的建构区块。开发者撰写并拥有JUnit测试。每当一个开发反复 (iteration)完成,这个测试便包裹成为交付软件的一部份 提供一种沟通的方式,「这是我交付的软件并且是通过测试的。」
            JUnit测试是以Java写成的。
    使用Java测试Java软件形成一个介于测试及程序代码间的无缝(seamless)边界。在测试的控制下测试变成整个软件的扩充同时程序代码可以被重整。Java编译器的单元测试静态语法检查可已帮助测试程序并且确认遵守软件接口的约定。
    一段测试的程序代码无法单独的执行,它需要是执行环境的一部份。同时,它需要自动执行的单元测试--譬如在系统中周期性的执行所有的测试以证明没有任何东 西被破坏。由于单元测试需要符合特定的准则:一个成功的测试不应该是人工检查的(那可要到天荒地老了啊),一个未通过测试的失败应可以产出文件以供诊断修 改。而Junit可以提供给我们这些便利.。这样所有测试开发者所需撰写的只是测试码本身了。跟optimizeit、Jtest那些昂贵而又超级麻烦的 tool比较起来,其利昭然可见!


  • 数据库的单元测试。

    2007-09-16 13:48:33

    数据库的单元测试。
    这些笔录是我关于已完成的数据库功能测试的一些心得。其中的例子是用java语言编写的,但我认为这些想法对于大多数编程环境都普遍适用。当然,我仍致力于寻找更佳的解决方案。
      现实的问题是这样的:你有一个SQL数据库,一些存储过程和一个介于应用程序和数据库之间的中间层。你怎样在其中插入测试代码从而保证在数据库中数据存取功能的实现?
    一、 为什么会有这样的问题?
      我猜想有些,可能不完全是大多数的数据库开发过程都是这样的:建立数据库,编写存取数据到数据库的代码,编译并运行,用一个查询语句查验所列的数据是 否正确显示。如果能正确显示那就大功告成了。 然而,这种靠眼睛来检测的弊端在于:你不经常进行这样的检验,而且这种检验是不完全的。存在这样的可能性,当你对系统进行了修改,过了几个月后,你无意中 破坏了系统,从而导致数据的丢失。作为一个编程人员,你可能不会花很多时间来检查数据本身,这就使错误的数据要经过较长的时间才能暴露出来。我曾经参与一 个建立网站的项目,该项目中在注册时有一个必填数据在大半年中没有被发现未实际输入进数据库。尽管公司市场部曾经提出他们需要这一信息,但因为这项数据从 来没有人去看它,直接导致了这一问题在很长时间内没有被发现。 自动化测试,由于它能经常测试而且测试范围较广,降低了数据丢失的风险。我发现它能使我更心安理得地休息。当然,自动化测试还有其他一些好处,他们本身就 是代码编写的范例,也可以作为文档,便于你修改别人编写的原始程序,从而减少检测所需的时间。
    二、 什么是我们所谈论的测试?
      设想有一个非常简单的用户数据库,包括用户电子信箱和一个标志,用来指示邮件地址是否被弹回。你的数据库程序应该包括插入、修改、删除和查询等方法
      插入方法会调用一个存储过程将数据写入数据库。为了叙述方便,这里省去了一些细节,大致的程序如下所示:
    public class UserDatabase
    {
    ...
    public void insert(User user)
    {
    PreparedStatement ps = connection.prepareCall("{ call User_insert(?,?) }");
    ps.setString(1, user.getEmail());
    ps.setString(2, user.isBad()); // In real life, this would be a boolean.
    ps.executeUpdate();
    ps.close();
    }
    ...
    }
      而我认为的测试代码应为:
    public class TestUserDatabase extends TestCase
    {
    ...
    public void testInsert()
    {
    // Insert a test user:
    User user = new User("some@email.address");
    UserDatabase database = new UserDatabase();
    database.insert(user);
    // Make sure the data really got there:
    User db_user = database.find("some@email.address");
    assertTrue("Expected non-null result", db_user != null);
    assertEquals("Wrong email", "some@email.address", db_user.getEmail());
    assertEquals("Wrong bad flag", false, db_user.isBad());
    }
    ...
    }
      可能你还有更多测试代码。(注意一些测试,例如对date类的测试)。
      assertTrue和assertEquals方法进行条件测试。如果测试失败,他们将返回诊断消息。其重点是这些测试都基于一个测试框架自动执 行,并给出测试成败的标志。这些测试都基于用java语言编写的测试框架Junit类(程序附后)。这一框架也能适应其他诸如C, C++, Perl, Python, .NET (all languages), PL/SQL, Eiffel, Delphi, VB等语言环境。
      下一个问题就是:我们有测试,但我们怎样保证测试数据和实际数据能严格区分?


    三、 不同的鉴别方法
      在开始之前,我必须指出你最好有一个测试用的数据库,你可能更想在非正式的数据库中实践我讲的东西。
      第一种方法是手工在数据库中输入一些预先知道的测试性数据,例如在邮件地址中输入“testuser01@test.testing”。如果你正在测试数据库的查询功能,你能预先知道,比如说有五个,数据库记录是以“@test.testing”结尾的。
      由以上方式插入的数据必须由测试本身进行必要的维护。例如,测试必须负责删除所建立的测试数据,而避免对实际数据进行操作,从而保证整个数据库处于完好状态。
      这种方法还是存在以下问题:
      你不得不和其他编程人员进行数据协调——假设他们也有他们自己的测试数据库。
      在数据库中有些特殊的数据并不正确,如一些特别的邮件地址和被保留饿编号前缀。
      在某些情况下,你将不能用一些特殊的数据来区分测试数据和实际数据,这就比较棘手。例如,某条数据由一些整数型字段构成,而作为测试用的数值都看起来较为合理。
      你的测试只限于你为测试所保留的某些特殊值,这意味着你将小心地选择那些特殊值。
      如果数据对时间敏感,那对数据库的维护将更为困难。例如,数据库中有产品销售提议,而该提议只在明确的时间段里有效。 我曾经试着做过修改。例如,在数据库中增加“is_test”字段作为区分测试数据的标志,从而避免特殊值的问题。但由此带来的问题是,你的测试代码将只 测试那些标记为测试的数据,而你的正式代码却要处理那些未标记为测试的数据。如果你的测试在这方面有区别,你事实上并不在测试同一代码。
    四、 你需要四个数据库
      有些想法认为一个好的测试是足够充分的并能建立测试所需要的全部数据。如果你能在测试进行前就明确知道数据库所处的状态,测试可以进行一些简化。一个简化的方法是建立一个独立的单元测试数据库用于测试程序,测试程序在开始进行前清除测试数据库中的全部数据。
      在代码中,你可以编写一个dbSetUp方法,如下所示:
    public void dbSetUp()
    {
    // Put the database in a known state:
    // (stored procedures would probably be better here)
    helper.exec("DELETE FROM SomeSideTable");
    helper.exec("DELETE FROM User");

    // Insert some commonly-used test cases:
    ...
    }
      任何数据库测试程序都将在做任何事前首先调用dbSetUp方法,它将使测试数据库处于一种已知状态(大部分情况下是空数据库状态)。这种做法具有以下的优点:
      所有的测试数据都在代码层和其他编程人员进行交流,因此没有必要进行外部测试数据协调。
      无须测试用的特殊数据的介入。
      简单而容易理解的一种方法。
      在每一次测试前删除和插入数据可能会花较多时间,但是由于测试用的数据量相对较小,我认为这种方法比较快捷,特别是在测试一个本地数据库时。
      这种做法不利的一面是你需要至少两个数据库。但是请记住,他们在必要是都可以在同一个服务器上运行。采用这种方法,我用了四个数据库,另外两个在紧急关头时使用,具体如下:
      1. 实际使用数据库,包含实际数据。在这个数据库中不进行测试,确保数据的完整性。
      2. 你的本地开发数据库,用来进行大部分的测试。
      3. 一个加入一定量数据的本地开发数据库,可能和其他编程人员共享,用来运行应用程序并检测是否能在实际使用的数据库上运行,而不是照搬实际使用数据库中的全 部数据。从严格意义上说你可能并不需要这一数据库,但这一数据库能确保应用程序在有大量数据的数据库中顺利运行。
      4. 一个发布数据库,或称集成数据库,用来在正式发布前进行一系列测试,从而确保对所有本地数据库的修改都得到确认。如果你一个人开发,你可以省略这个数据 库,但你必须确保所有对数据结构和存储过程的修改都在实际使用数据库中得到确认。 在有多个数据库的情况下,你要确保不同数据库间结构的同步:如果你在测试数据库中改变表的定义或存储过程,你必须记得在实际使用的服务器上进行同样的修 改。发布数据库的作用就是提醒你进行这些修改。另外,我发现如果代码控制系统能将提交时的注释用邮件形式自动发给整个开发组,那将给团队开发带来较大帮 助。CVS就能做到这一点,我希望你能利用这一功能。


    五、 在合适的数据库中进行测试
      在这种情况下,你必须连接正确的数据库。在实际使用数据库中进行测试有可能删除所有的有用数据,这点令我十分害怕。
      有几种办法能避免此类悲剧的发生。例如,比较普遍的做法是将数据库连接设置记录在初始文件中,从而明确哪一个是测试数据库。你也可以通过初始文件进行本地数据库的测试,而用其他指定方法连接实际使用数据库。
      在java代码中,初始文件可能如下所示;
    myapp.db.url=jdbc:mysql://127.0.0.1/mydatabase
      这一连接字符串用来连接数据库。你可以添加第二个连接字符串来区分测试数据库:
    myapp.db.url=jdbc:mysql://127.0.0.1/mydatabase
    myapp.db.testurl=jdbc:mysql://127.0.0.1/my_test_database
      在测试代码中,你可以检查并确保在连接到测试数据库后应用程序才能继续运行:
    public void dbSetUp()
    {
    String test_db = InitProperties.get("myapp.db.testurl");
    String db = InitProperties.get("myapp.db.url");
    if (test_db == null)
    abort("No test database configured");
    if (test_db.equals(db))
    {
    // All is well: the database we're connecting to is the
    // same as the database identified as "for testing"
    }
    else
    {
    abort("Will not run tests against a non-test database");
    }
    }
      另一个技巧是,如果你有一个本地测试数据库,测试程序能通过提供IP地址或主机名进行检测。如果不是“localhost/127.0.0.1”,这就有连接在实际使用数据库上进行测试的风险。
    六、 关于测试日期的体会
      如果你想存储日期信息,你大概想确认你存的日期信息是否正确。请注意以下几点。
      首先先问自己,是谁创建该日期。如果是你的应用程序,那验证比较简单,因为你可以通过查看数据库中的具体日期进行比较。如果是数据库本身创建该日期, 可能作为一个缺省字段,那你可能就会有些问题。例如,你能确保你代码所代表的时区和数据库的时区一致吗?从没有听说过数据库是以格林尼治标准时间为准显示 时间和日期的。你能确保运行应用程序的计算机上的时间和数据库所在计算机上的时间保持一致吗?如果不是,你必须在进行时间的比较时留出一定的误差。
      如果你遇到这些情况,有些事是你可以做的:
      如果你预先知道所用的时区,在测试前将所有日期和时间全部转换成那个时区的日期和时间。
      在比较时间时设立一定的误差,比如说几分钟、几小时或几个月。看上去缺乏说服力,但至少它能捕获诸如日期为空或1970年1月1日等错误。
    七、 总结
      在本文中,我想说:
      单元数据库测试是一件值得做的事;
      如果你能给一系列测试程序一个对应的数据库,测试本身并不非常可怕。
      还有其他方法能解决这一问题。我还不能确信模仿对象(Mock Object)这一方法。就我对这一方法的理解,模仿对象模拟了一个系统中间层(在本文中,是数据库操作系统),使得模仿的数据库总能返回你想要的数据。 我比较欣赏这一概念,它鼓励你对测试进行分层,可能划分成SQL方面的测试和Java语言方面的测试,从而对模仿的ResultSet对象进行测试。
      我比较关注那些能导致一次能使两个或两个以上的数据表产生变化的操作。在这种情况下,用模仿对象方法进行数据库的维护和实现比较困难。当然,我还要找到一种好方法进行数据库中SQL方面的测试,从而确认数据被正确地存储到数据库中。


  • 单元测试指导

    2007-09-16 13:44:24

    单元测试指导
    这是交大慧谷软件测试沙龙二期张华先生与大家分享的内容,很有用的

    单元测试指导

    一、单元测试环境配置测试
    1. 网络连接是否正常
    2. 网络流量负担是否过重
    3. 软件测试平台是否可选
    4. 如果(3),是否在不同的软件测试平台进行软件测试
    5. 所选软件测试平台的版本(包括Service Pack)是否正确
    6. 所选软件测试平台的参数设置是否正确
    7. 所选软件测试平台上正在运行的其它程序是否会影响测试结果
    8. 画面的分辨率和色彩设定是否正确
    9. 对硬件测试平台的要求和支持程度

    二、代码测试
    A 静态测试
    1. 同一程序内的代码书写是否为同一风格
    2. 代码布局是否合理、美观
    3. 程序中函数、子程序块分界是否明显
    4. 注释是否符合既定格式
    5. 注释是否正确反映代码的功能
    6. 变量定义是否正确(长度、类型、存储类型)
    7. 子程序(函数和方法)接受的参数类型、大小、次序是否和调用模块相匹配合
    8. 函数的返回值类型是否正确
    9. 程序中是否引用了未初始化变量
    10. 数组和字符串的下标是否为整数
    11. 数组和字符串的下标是否在范围内(不“越界”)
    12. 进行数组的检索及其它操作中,是否会出现“漏掉一个这种情况”
    13. 是否在应该使用常量的地方使用了变量(例:数组范围检查)
    14. 是否为变量赋予不同类型的值
    15. (14)的情况下,赋值是否符合数据类型的转换规则
    16. 变量的命名是否相似
    17. 是否存在声明过,但从未引用或者只引用过一次的变量
    18. 在特定模块中所有的变量是否都显式声明过
    19. 非(18)的情况下,是否可以理解为该变量具有更高的共享级别
    20. 是否为引用的指针分配内存
    21. 数据结构在函数和子程序中的引用是否明确定义了其结构
    22. 计算中是否使用了不同数据类型的变量
    23. 计算中是否使用了不同的数据类型相同但长度不同的变量
    24. 赋值的目的变量是否小于赋值表达式的值
    25. 数值计算是否会出现溢出(向上)的情况
    26. 数值计算是否会出现溢出(向下)的情况
    27. 除数是否可能为零
    28. 某些计算是否会丢失计算精度
    29. 变量的值是否超过有意义的值
    30. 计算式的求值的顺序是否容易让人感到混乱
    31. 比较是否正确
    32. 是否存在分数和浮点数的比较
    33. 如果(32),精度问题是否会影响比较
    34. 每一个逻辑表达式是否都得到了正确表达
    35. 逻辑表达式的操作数是否均为逻辑值
    36. 程序中的Begin…End和Do…While等语句中,End是否对应
    37. 程序、模块、子程序和循环是否能够终止
    38. 是否存在永不执行的循环
    39. 是否存在多循环一次或少循环一次的情况
    40. 循环变量是否在循环内被错误地修改
    41. 多分支选择中,索引变量是否能超过可能的分支数
    42. 如果(41),该情况是否能够得到正确处理
    43. 全局变量定义和用法在各个模块中是否一致
    44. 是否修改了只作为输入用的参数
    45. 常量是否被作为形式参数进行传递

    B 动态测试
    1. 测试数据是否具有一定的代表性
    2. 测试数据是否包含测试所用的各个等价类(边界条件、次边界条件、空白、无效)
    3. 是否可能从客户那边得到测试数据
    4. 非(3)的情况下,所用的测试数据是否具有实际的意义(客户业务上的)
    5. 是否每一组测试数据都得到了执行
    6. 每一组测试数据的测试结果是否与预期结果一致
    7. 文件的属性是否正确
    8. 打开文件语句是否正确
    9. 输入/输出语句是否与格式说明书所记述的一致
    10. 缓冲区大小与记录长度是否匹配
    11. 使用文件前是否已打开了文件
    12. 文件结束条件是否存在
    13. 产生输入/输出错误时,系统是否进行检测并处理
    14. 输出信息中是否存在文字书写错误和语法错误
    15. 数字输入框是否接受数字输入
    16. (15)的情况下、数字是否按既定格式显示
    17. 数字输入框是否拒绝字符串和“非法”数字的输入
    18. 组合框是否的能够进行下拉选择
    19. 组合框是否能够进行下拉多项选择
    20. 对于可添加数据组合框,添加数据后数据是否能够得到正确显示和进行选择
    21. 列表框是否能够进行选择
    22. 多项列表框是否能够进行多数据项选择
    23. 日期输入框是否接受正确的日期输入
    24. 日期输入框是否拒绝错误的日期输入
    25. 日期输入框在日期输入后是否按既定的日期格式显示日期
    26. 单选组内是否有且只有一个单选钮可选
    27. 如果单选组内无单选钮可选,这种情况是否允许存在
    28. 复选框组内是否允许多个复选框(包括全部可选)可选
    29. 如果复选框组内无复选框可选,这种情况是否允许存在
    30. 文本框及某些控件拒绝输入和选择时显示区域是否变灰或按既定规约处理
    31. 文本框中数据格式(大小、对齐方向、颜色、背景)是否符合规范
    32. 密码输入框是否按掩码的方式显示
    33. 控件是否存在默认输入值,若存在,默认值是否得到显示和提交
    34. Cancel之类的按钮按下后,控件中的数据是否清空复原或按既定规约处理
    35. Submit之类的按钮按下后,数据是否得到提交或按既定规约处理
    36. 异常信息表述是否正确
    37. 软件是否按预期方式处理错误
    38. 文件或外设不存在的情况下是否存在相应的错误处理
    39. 软件是否严格的遵循外设的读写格式
    40. 产生的文件和数据表的格式是否正确
    41. 产生的文件和数据表的计算结果是否正确
    42. 打印的报表是否符合既定的格式
    43. 错误日志的表述是否正确
    44. 错误日志的格式是否正确

    C GUI测试
    1. 窗体是否能够基于相关的输入或菜单命令适当的打开
    2. 窗体是否能够改变大小、移动和滚动
    3. 窗体的数据是否能够利用鼠标、功能键、方向箭头和键盘操作
    4. 当窗体被覆盖并重新调用后,窗体是否能够正确再生
    5. 窗体相关的功能是否可以操作
    6. 是否显示相关的下拉菜单、工具条、滚动条、对话框、按钮、图标和其他控制,既能正确显示又能调用
    7. 显示多窗体时,窗体名称是否能够正确表示
    8. 活动窗体是否能够被反显加亮
    9. 多用户联机时所有窗体是否能够实时更新
    10. 鼠标无规则点击时是否会产生无法预料的结果
    11. 窗体声音及提示是否符合既定编程规则
    12. 窗体是否能够被关闭
    13. 窗体控件的大小、对齐方向、颜色、背景等属性的设置值是否和程序设计规约相一致
    14. 窗体控件布局是否合理、美观
    15. 窗体控件TAB顺序是否从左到右,从上到下
    16. 窗体焦点是否按照编程规范落在既定的控件上
    17. 窗体画面文字(全、半角、格式、拼写)是否正确
    18. 鼠标有多个形状时是否能够被窗体识别(如漏斗状时窗体不接受输入)
  • 单元测试的基本方法[转帖]

    2007-09-16 13:41:25

    单元测试的对象是软件设计的最小单位——模块。单元测试的依据是详细设描述,单元测试应对模块内所有重要的控制路径设计测试用例,以便发现模块内部的错误。单元测试多采用白盒测试技术,系统内多个模块可以并行地进行测试。
        单元测试任务
      单元测试任务包括:1 模块接口测试;2 模块局部数据结构测试;3 模块边界条件测试;4 模块中所有独立执行通路测试;5 模块的各条错误处理通路测试。
      模块接口测试是单元测试的基础。只有在数据能正确流入、流出模块的前提下,其他测试才有意义。测试接口正确与否应该考虑下列因素:
      1 输入的实际参数与形式参数的个数是否相同;
      2 输入的实际参数与形式参数的属性是否匹配;
      3 输入的实际参数与形式参数的量纲是否一致;
      4 调用其他模块时所给实际参数的个数是否与被调模块的形参个数相同;
      5 调用其他模块时所给实际参数的属性是否与被调模块的形参属性匹配;
      6调用其他模块时所给实际参数的量纲是否与被调模块的形参量纲一致;
      7 调用预定义函数时所用参数的个数、属性和次序是否正确;
      8 是否存在与当前入口点无关的参数引用;
      9 是否修改了只读型参数;
      10 对全程变量的定义各模块是否一致;
      11是否把某些约束作为参数传递。
      如果模块内包括外部输入输出,还应该考虑下列因素:
      1 文件属性是否正确;
      2 OPEN/CLOSE语句是否正确;
      3 格式说明与输入输出语句是否匹配;
      4缓冲区大小与记录长度是否匹配;
      5文件使用前是否已经打开;
      6是否处理了文件尾;
      7是否处理了输入/输出错误;
      8输出信息中是否有文字性错误;
      检查局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确。局部数据结构往往是错误的根源,应仔细设计测试用例,力求发现下面几类错误:
      1 不合适或不相容的类型说明;
      2变量无初值;
      3变量初始化或省缺值有错;
      4不正确的变量名(拼错或不正确地截断);
      5出现上溢、下溢和地址异常。
      除了局部数据结构外,如果可能,单元测试时还应该查清全局数据(例如FORTRAN的公用区)对模块的影响。
      在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。此时设计测试用例是为了发现因错误计算、不正确的比较和不适当的控制流造成的错误。此时基本路径测试和循环测试是最常用且最有效的测试技术。计算中常见的错误包括:
      1 误解或用错了算符优先级;
      2混合类型运算;
      3变量初值错;
      4精度不够;
      5表达式符号错。
      比较判断与控制流常常紧密相关,测试用例还应致力于发现下列错误:
      1不同数据类型的对象之间进行比较;
      2错误地使用逻辑运算符或优先级;
      3因计算机表示的局限性,期望理论上相等而实际上不相等的两个量相等;
      4比较运算或变量出错;
      5循环终止条件或不可能出现;
      6迭代发散时不能退出;
      7错误地修改了循环变量。
      一个好的设计应能预见各种出错条件,并预设各种出错处理通路,出错处理通路同样需要认真测试,测试应着重检查下列问题:
      1输出的出错信息难以理解;
      2记录的错误与实际遇到的错误不相符;
      3在程序自定义的出错处理段运行之前,系统已介入;
      4异常处理不当;
      5错误陈述中未能提供足够的定位出错信息。
      边界条件测试是单元测试中最后,也是最重要的一项任务。众的周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。
  • 单元测试的基本方法

    2007-09-16 13:32:02

    单元测试的基本方法
      单元测试的对象是软件设计的最小单位——模块。单元测试的依据是详细设描述,单元测试应对模块内所有重要的控制路径设计测试用例,以便发现模块内部的错误。单元测试多采用白盒测试技术,系统内多个模块可以并行地进行测试。

    单元测试任务


      单元测试任务包括:1 模块接口测试;2 模块局部数据结构测试;3 模块边界条件测试;4 模块中所有独立执行通路测试;5 模块的各条错误处理通路测试。


      模块接口测试是单元测试的基础。只有在数据能正确流入、流出模块的前提下,其他测试才有意义。测试接口正确与否应该考虑下列因素:
      1 输入的实际参数与形式参数的个数是否相同;
      2 输入的实际参数与形式参数的属性是否匹配;
      3 输入的实际参数与形式参数的量纲是否一致;
      4 调用其他模块时所给实际参数的个数是否与被调模块的形参个数相同;
      5 调用其他模块时所给实际参数的属性是否与被调模块的形参属性匹配;
      6调用其他模块时所给实际参数的量纲是否与被调模块的形参量纲一致;
      7 调用预定义函数时所用参数的个数、属性和次序是否正确;
      8 是否存在与当前入口点无关的参数引用;
      9 是否修改了只读型参数;
      10 对全程变量的定义各模块是否一致;
      11是否把某些约束作为参数传递。


      如果模块内包括外部输入输出,还应该考虑下列因素:
      1 文件属性是否正确;
      2 OPEN/CLOSE语句是否正确;
      3 格式说明与输入输出语句是否匹配;
      4缓冲区大小与记录长度是否匹配;
      5文件使用前是否已经打开;
      6是否处理了文件尾;
      7是否处理了输入/输出错误;
      8输出信息中是否有文字性错误;


      检查局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确。局部数据结构往往是错误的根源,应仔细设计测试用例,力求发现下面几类错误:
      1 不合适或不相容的类型说明;
      2变量无初值;
      3变量初始化或省缺值有错;
      4不正确的变量名(拼错或不正确地截断);
      5出现上溢、下溢和地址异常。


      除了局部数据结构外,如果可能,单元测试时还应该查清全局数据(例如FORTRAN的公用区)对模块的影响。


      在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。此时设计测试用例是为了发现因错误计算、不正确的比较和不适当的控制流造成的错误。此时基本路径测试和循环测试是最常用且最有效的测试技术。计算中常见的错误包括:
      1 误解或用错了算符优先级;
      2混合类型运算;
      3变量初值错;
      4精度不够;
      5表达式符号错。


      比较判断与控制流常常紧密相关,测试用例还应致力于发现下列错误:
      1不同数据类型的对象之间进行比较;
      2错误地使用逻辑运算符或优先级;
      3因计算机表示的局限性,期望理论上相等而实际上不相等的两个量相等;
      4比较运算或变量出错;
      5循环终止条件或不可能出现;
      6迭代发散时不能退出;
      7错误地修改了循环变量。


      一个好的设计应能预见各种出错条件,并预设各种出错处理通路,出错处理通路同样需要认真测试,测试应着重检查下列问题:
      1输出的出错信息难以理解;
      2记录的错误与实际遇到的错误不相符;
      3在程序自定义的出错处理段运行之前,系统已介入;
      4异常处理不当;
      5错误陈述中未能提供足够的定位出错信息。


      边界条件测试是单元测试中最后,也是最重要的一项任务。众的周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。


    单元测试过程


      一般认为单元测试应紧接在编码之后,当源程序编制完成并通过复审和编译检查,便可开始单元测试。测试用例的设计应与复审工作相结合,根据设计信息选取测试数据,将增大发现上述各类错误的可能性。在确定测试用例的同时,应给出期望结果。


      应为测试模块开发一个驱动模块(driver)和(或)若干个桩模块(stub),下图显示了一般单元测试的环境。驱动模块在大多数场合称为“主程序”,它接收测试数据并将这些数据传递到被测试模块,被测试模块被调用后,“主程序”打印“进入-退出”消息。


      驱动模块和桩模块是测试使用的软件,而不是软件产品的组成部分,但它需要一定的开发费用。若驱动和桩模块比较简单,实际开销相对低些。遗憾的是,仅用简单的驱动模块和桩模块不能完成某些模块的测试任务,这些模块的单元测试只能采用下面讨论的综合测试方法。


      提高模块的内聚度可简化单元测试,如果每个模块只能完成一个,所需测试用例数目将显著减少,模块中的错误也更容易发现。





  • 微软高级开发者管理峰会演讲摘要:产品质量的基石

    2007-09-04 14:23:43

    微软高级开发者管理峰会演讲摘要:产品质量的基石
    来自:微软 蔡锫
    (2002.12.11)
    一.团队组织
    1.常见问题
    没有人愿意做测试
    觉得养不起那么多测试人员
    开发人员不遵循规范,随心所欲
    项目经理事必躬亲,分身乏术
    2.微软团队模型

    各角色的职责
    角色        职责
    项目经理        编写功能规范,协调各角色关系
    产品经理        客户联系的桥梁,进行需求分析
    用户教育        让产品容易使用
    发布经理        保证产品顺利发布
    二.项目管理
    1.常见问题
    无法决定项目所需的资源(人力和预算)
    无法决定项目的进度表
    无法控制外包项目的进度和质量
    2.微软项目管理-- 多里程碑式流程
    每个里程碑完成部分功能
    便于团队集中力量完成一个又一个功能
    提供多个机会以适应需求的更改
    如何完成一个里程碑
    步骤一: 达成共识
    基本完成需求调研和分析 (产品经理负责)
    确定大方向和长中短期目标
    所有角色都参与讨论并真正认同结论
    产生的文档:
    常见用户情景:覆盖80%以上功能
    Vision:言简意赅地说明大方向,并有激励团队的作用
    步骤二: 完成项目计划
    编写详细的功能规范(项目经理负责)
    在编程前想清楚所有功能流程,并引导用户明确需求
    所有角色都参与审阅功能规范
    制订开发计划和进度表(开发团队)
    制订测试计划和进度表(测试团队)
    分配资源(人力和预算)
    形成项目综合计划和综合进度表
    产生的文档:
    功能规范,开发计划,测试计划(用例),项目综合计划
    开发进度表,测试进度表,综合进度表
    步骤三: 完成功能
    开发人员分别完成自己的功能
    使用版本控制工具
    使程序员及时check out和check in,避免积累大量代码
    及时进行模块间的整合,及时发现问题(daily build)
    对每一项可测试的功能进行测试,无需等待
    使用测试用例工具,对功能进行完整和重复的检验
    使用BMS进行缺陷跟踪
    记录所有程序问题
    实现解决Bug的自动流程
    按照综合进度表不断检查进度
     
    使用的工具:
    版本控制工具 VSS
    缺陷跟踪工具 Raid/BMS
    测试用例管理工具
    步骤四: 稳定与发布
    测试组全面地测试功能,包括性能和稳定性
    开发组全力配合解决Bug
    使用BMS进行
    监测质量情况
    预测发布日期
    专家会诊机制:
    决定Bug的优先度
    决定哪些Bug可以等到下个里程碑或版本中解决
    决定由谁解决某个Bug
     
    使用的工具:
    版本控制工具 VSS
    缺陷跟踪工具 BMS
    测试用例管理工具
    三. 微软的开发管理经验:100%以Bug为核心

    1.Bug 及常见类型
    功能未实现,和规格说明书不一致
    不能工作:死机,没反应
    不兼容
    边界条件
    界面、消息、提示不够准确,不友好
    把尚未完成的工作也作为一个Bug
    文档与帮助信息中的缺陷也是Bug
    2.RAID/BMS的基本功能

    完整的Bug数据库
    整个产品组的中央记录和控制
    强大的查询功能,有效地跟踪项目的状态
    所有的记录无法删除,对于每个记录只能一直添加内容
    丰富的报表功能,为产品发布提供判断标准
    3.Bug 记录中的有效信息 状态
    负责人
    问题种类
    严重级
    优先级
    修改时间
    登记时间
    缺陷来源
    解决方案
    运行环境
    缺陷关联
    附件
    附图
    缺陷细节

    4.Bug 的严重程度
    死机,数据丢失,主要功能组完全丧失,系统悬挂
    主要功能丧失,导致严重的问题,或致命的错误声明
    次要功能丧失, 不太严重,如提示信息不太准确
    微小的问题,对功能几乎没有影响,产品及属性仍可使用. 如有个错别字
    5.激活的Bug数量的趋势
    代码完成前:很少
    代码完成后:增长很快
    接近Beta: 下降
    接近RC: 奔向零
    产品质量和里程碑的信号
    每天新建的Bug 与 修正的 Bug 相比较
    Active 状态 Bug 的总数
    四.微软的一天
    1. 让我们看看项目中每个角色的一天是如何度过的
    开发
    测试
    项目经理
    注:里程碑的每个阶段每个角色的工作有不同侧重点,我们以“完成功能”阶段为例

    微软的一天从几点开始?
    答案:半夜
    为什么?
    因为Daily Build是所有工作的核心,而且是在半夜自动启动。
    每日构造Daily Build
    你知道自己所用Windows的版本号吗?
    Daily Build的意义:
    模块得以及时整合
    要求程序员及时把最新代码放入代码库
    用脚本语言和编译/链接工具实现
    BVT Build Verification Test
    对Build进行验证
    Blocking Bug
    让Build无法完成的问题
    BVT中发现的问题
    2.程序员每天上班前最担心什么?
    答案:因为自己昨天的代码check-in,造成Blocking Bug.
    为什么?
    因为每天的Build是所有人当天工作的基础:
    程序员需要Build验证与其他模块的接口
    测试需要Build发现新Bug,并验证新Build中已解决的Bug
    有Blocking Bug怎么办?
    解决问题,并对今天的Build打Patch。
    开发人员的正事
    经历对Build的提心吊胆和争分夺秒之后,第一件事做什么
    答案:打开缺陷跟踪工具,查看指定给自己的Bug,解决高优先度的Bug。因为质量重于新功能。
    接下来,开发人员会…
    从版本控制工具中Check out代码
    修改代码(解决Bug或实现新功能)
    取得版本工具中最新变化,在本机Build和单元测试
    请开发组同事作Code Review
    Check in代码

    3.测试人员第一件事做什么?
    答案:打开Raid/BMS,查看指定给自己的Bug,验证已解决的Bug。
    接下来,测试人员会…
    根据测试用例检验今天的Build
    在Raid/BMS中记录新发现的Bug
    4.专家会诊
    参加者:项目经理和开发组长、测试组长
    通过Raid/BMS评估每个未解决的Bug
    决定Bug优先度
    可否等到下个里程碑或版本解决?
    谁来解决
    预测项目实际进度和发布时间
    缺陷走势图

    5.回顾微软的一天
    构造: daily build
    开发: 解决blocking bugs, 实现功能, check-out, code review, check-in
    测试: BVT, 使用测试用例进行测试
    项目经理/组长: 专家会诊
    6.微软的做法解决了那些常见问题?
    质量问题
    以前解决过的问题发布时又出现了,需要返工
    无法预估发布时间 过早发布,带来质量和维护问题
    测试发现的问题被忘却或不了了之
    无法衡量测试员和开发员的工作
    程序中的问题往往在发布后才发现
    文档管理问题
    文档与程序脱节,文档成为程序结果的描述
    项目组把写文档看成负担
    团队协调问题
    开发人员各自为战,进行整合时发现模块衔接中的严重问题 需要作大的改动
    没有保管好公司以往的版本和代码,无法满足用户对旧版本的更改要求
    开发人员离职对项目带来很大冲击,没有人知道代码在哪,或无法读懂
    五.提高软件管理的步骤
    1. 使用Raid/BMS,将流程管理自动化
    2. 使用测试用例管理工具
    3. 使用文档管理工具
    4. 使用版本控制工具,进行Daily Build
    5. 建立代码标准
    6. 建立Code Review机制
    7. 建立专家会诊机制
    8. 建立团队沟通机制
    9. 根据需要调整团队结构
  • 谈项目管理和软件测试 过程

    2007-08-25 14:51:21

    1. 软件测试在公司的组织保障是基础
    1.1 研发部组织结构介绍
    以华友公司研发部的组织结构为例,测试部门属于研发部副总裁直接管理,见如下结构图
    公司研发部的组织结构图

    对于从事软件研发的组织来说,工作类型至少包括项目管理、产品设计、编码、测试、质量保证和软件配置管理,以及其它人员,如文档编制人员和美工人员/系统硬件管理人员等。根据职能需要,可以以半独立方式进行部门和项目的矩阵管理,即职员要对项目经理/组长负责,也要对部门经理/总监负责,工作考核由双方共同完成,标准的组织应包括技术开发部/组(主要是编码和设计人员),产品开发部/组(产品需求和项目管理),测试部/组,配置管理部/组(因为配置管理人员基本上是按20个技术人员配一个配置管理人员,所以一般部门规模较小,或者只是配置管理组),软件质量保障部/组,其它部/组(如系统/文档/美工等)。华友公司组织结构中,研发部是公司软件研发的核心部门
    产品研发Ⅰ部、Ⅱ部、和应用研发部主要负责:
    与软件产品部或内容产品部配合,协助完成内容产品的可行性、合理性分析;
    平台、网关、应用产品的研发项目的立项和方案评审;
    研发项目的概要设计、详细设计工作;
    研发项目的编码、单元测试工作;
    组织公司相关部门进行研发产品的培训;
    协助相关部门做好产品的售前技术支持工作;
    协助相关部门进行软件的安装与调试;
    根据相关部门的要求做好产品的售后服务工作,保障软件的运行正常。
    测试部隶属研发部,主要职责如下:
    与内容产品部和软件产品部配合完成软件需求分析讨论,并根据需求说明书制订《项目测试方案》,编写《测试用例》,建立测试环境;
    负责完成研发部各开发组研发的软件产品开发过程和投入运营之前的新增软件和修改升级软件的模块测试和系统测试;
    建立、推广并维护实施软件版本管理系统CVS和VSS;
    使用并维护软件缺陷管理系统Bugzilla,负责软件问题解决过程跟踪记录;
    负责推广实施软件开发文档规范化工作,管理研发产品相关文档;
    负责配合软件运维部门等对于新业务软件或修改升级业务软件的上线测试工作,并提供上线测试报告;
    负责监督软件开发流程的执行,并负责提出软件开发过程改进建议,提高软件产品质量。
    1.2 软件产品研发各部门的组织结构分解
    1)华友公司从2003年10月开始,对项目组制订明确指标的独立考核,各开发部门是技术总监带队,再细分各项目经理具体负责项目计划和执行,对项目具体开发成员进行分工。对于测试部门制订年度测试部门任务计划/考核表,如SMS业务销售额指标完成:目标1:9900万(奖金提取比例为0.01%);目标2:16800万(奖金提取比例为0.02%);目标3:23200万(奖金提取比例为0.03%)
    详细给出财务目标和业务运营目标。
    在每周的开发经理工作会议上交流报告任务进展情况,并提出最近测试需求,测试部门经理负责制订测试计划、测试用例和测试实施方案,安排测试工程师与对应的开发人员交流完成测试执行工作。测试部经理负责开发流程管理和人力资源、测试用软硬件资源调配,需要与研发之外的部门定期交流掌握下周或近期可能测试任务,所有其他外部接口都由测试部经理负责完成,与其他项目组和产品部门协调项目进度。
    2) 工作汇报关系为:
    开发部门:Team Member->Team Leader->研发总监->研发部副总裁->总裁。
    测试部门:测试工程师->测试小组经理->测试部经理/总监->研发部副总裁->总裁。
    3)项目成员结构:
    公司通常的开发项目组为6到8个开发人员,最多不超过10人。
    华友公司的经过三次改造后的组织结构和项目组结构,各个业务部门分类非常细,任务明确,软件开发的每一个步骤都有专门的部门、专门的人员负责,从最基础的开发人员到负责统领全局的总监和副总裁,层层管理,沟通渠道畅通。而在软件测试上,由于有限的测试资源,首先体现在公司的组织结构上,集中表现为测试部门不得不面对公司级管理部门的缺失和管理的交叉上,没有质量管理部门,部门质量管理工作测试部门兼做。公司从成本角度考虑,测试部门规模较小,测试人员总数不超过10人,几乎每个测试人员接收处理10个开发人员的测试任务需求。从实际情况出发,首先明确测试部门和软件开发部门相对独立的组织关系,保证测试人员的工作不受开发小组的控制,实现测试客观、公证。华友公司要想有效地保障产品质量,首先就要在构架合理的组织结构和测试流程上下功夫,这就如同盖高楼首先要打好地基一样,地基不打牢,结构和流程不合理,其他方面再下功夫也是徒劳。
    从实践经验看,一年前首先成立测试部,把属于开发部门的测试工程师归口到独立的测试部门管理,其次建立规范的测试流程,与开发部门交流,要求每周提出测试需求,再根据现有的资源制订每周测试计划,同时向人力资源部门提出招聘计划,随着测试工作的成绩不断被开发部门和上级领导认可,再推广实施软件开发过程规范化的管理,通过测试实践的优良成绩来确立测试部门在公司的地位和作用,经过一年的奋斗测试部门从无到有,从最初两人到现在十人,软件配置管理和缺陷跟踪系统已经被60%的开发人员自愿使用和接收。 总结本人在华友一年多测试工作经验,深深体会到在国内从事软件项目开发难、从事软件测试和质量保证工作更难,需要具备扎实的技术功底同时,不断提高测试项目管理能力,寻找工作的突破口。世上无难事,只怕有心人,但是只要你努力献身于软件测试工作,打出一片天地是有可能的。(
    2.配置管理系统是项目经理的"眼睛",是软件测试有效实施的前提
    在软件质量体系的诸多支持活动中,配置管理系统处在支持活动的中心位置,它有机地把其它支持活动结合起来,形成一个整体,相互促 进,相互影响,有力地保证了质量体系的实施。建立公司配置管理系统很容易得到公司领导层的支持,几乎没人反对。更重要的是建立配置管理系统后测试人员的工作有了系统保证,测试工作的"矿藏资源"有了明确的位置,可以主动积极开展测试工作。
    2.1 项目管理存在的主要问题
    华友公司测试部门去年刚成立时,以建立、规范和推广使用配置管理系统CVS为突破口,同时建立缺陷跟踪系统Bugzilla提高测试流程的管理水平。我做为测试负责人首先分析华友公司几个软件项目在开发管理上的现状,。
    存在问题一、公司几个核心项目仍然过分分依赖少数个人的作用,没有建立起协同作战的氛围,没有科学的软件配置管理流程; 技术上只重视系统和数据库、开发工具的选择,而忽视配置管理工具的选择,导致即使有些项目有配置管理的规程,也由于可操作性差而搁浅。以上种种原因导致开发过程中普遍存在如下一些问题: 调查说明华友研发成员的变动的比率达到30%,几乎每周都有新加入的员工或者辞职人员, 一个新成员熟悉项目的最佳途径就是通过配置管理系统阅读项目文档,甚至阅读同行代码,达到快速学习、共同提高的目的。一个辞职人员可以利用配置管理系统保留部分一段时间工作,最大程度减少对项目开发造成的损失。
    存在问题二、开发管理松散。领导了解工作完成情况重视口头交流,忽视书面文档。有些部门主管无法确切得知项目的进展情况,项目经理也不知道各开发人员的具体工作,项目进展随意性很大,可"左"可"右"。"左"时按领导下达的"期限"进行,到期时,似乎一切已顺利完成,大家一阵胡弄,交差完成,反正领导看的是界面,至于里面是什么,留到施工时再说。施工时的工作因此变成了无法汇报、无法理清的无休止的维护。"右"时则项目工期无休止地延期。对我们软件工程来说,总的特点是先"左"后"右"。在领导面前表现"左",在用户面前表现"右"。有个测试人员经常利用上班时间学习英语,过了一个多月,看她依然如此,我做为项目领导进行批评教育,这名员工并不认为自己错了,她争辩,公司采取弹性工作时间,考核员工是分配的任务是否完成等理由。同时、我对她批评结果遭到她的恶意报复,她给有关领导报告新来的经理如何不懂公司业务,采取不适合公司的管理方式等,由于领导无法了解真相,使得我的工作在一段时间开展很困难,直到过去半年,这名员工辞职出国学习领导才明白发生了什么。
    存在问题三、项目之间沟通不够。各个开发人员各自为政,每个项目经理都像个"地主",编写的代码不仅风格各异,而且编码和设计脱节。每个项目组的人力资源和硬件资源成了"私有财产",自己人员即使暂时空闲,让他从事所谓的新技术研究,也不考虑友邻项目需要他们帮助的现状。本来开发中错误在所难免, 进展早一点的项目组或者人力资源强的项目组已经积累类似问题的解决经验,也不愿意分享给其它项目组。 开发大量重复, 留下大量难维护的代码。典型案例是有个短信项目D两年来在这个开发人员Y 的研发支持下运转效益很好,但是三个月之前,开发人员 Y因为待遇问题和公司领导谈判失败,提出辞职。项目D仍然在运行,但是最近移动公司规范修改、系统升级,需要修改程序,没人能看到及时更新的文档,尽管有一堆代码库,但是后来的程序员都没办法分析明白程序结构。公司领导出面请开发人员Y来协助,因为没有文档记录,Y忙于新公司的工作也不能解决修改。
    存在问题四、文档与程序严重脱节。软件产品是公司的宝贵财富,代码的重用率是相当高的,如何建好知识库,用好知识库对公司优质高效开发产品,具有重大的影响。但开发人员的一句名口号是:"叫我干什么都可以,但别叫我看别人的程序"。当然,开发人员的工作态度要转变,但客观上有一个很重要的原因是:前人留下的程序既无像样的文档(即使留下了文档 ,其与源程序也严重脱节),开发风格又不统一,就像一堆垃圾,要开发人员到垃圾中去捡破烂,从这个角度上看,开发人员的要求是合理的。
    存在问题五、测试工作不规范。仍然停留在"小姑娘做测试"的底水平上,传统的开发方式中,测试工作只是人们的一种主观愿望,根本无法提出具体的测试要求,加之开发人员的遮丑,测试工作往往是走一走过场,测试结果既无法考核又无法量化,当然就无法对以后的开发工作起指导作用。
    存在问题六、虽然项目施工时间不长,但软件版本更新周期过短,几乎每天都修改在线运行系统,且开发人员必须亲自现场或远程登陆操作,全国十几个地点软件内容多少都有点差别,这些差别都记录在几个骨干人物的脑袋里。 由于应用软件的特点,各个不同的施工点有不同的要求,开发人员要手工地保持多份不同的拷贝,即使是相同的问题,但由于在不同地方提出,由不同人解决,其做法也不同,程序的可维护性越来越差。久而久之,最后连自已都分不清楚了,代码的相互覆盖现象时有发生,且这苦水还无法倾诉,因为怕别人笑话,甚至别人问起,还得想法搪塞,可谓费尽苦心。
    2.2 建立配置管理系统,规范项目管理流程,建立知识库的同时节约项目费用
    针对以上问题, 利用自己在Beijing Precom Inc, 普天润汇等公司积累的经验,建立配置管理系统CVS, CVS 的全称是Current Version Control. CVS是一种GNU 软件包.由Intersolv公司开发,它明确的将源文件的存储和用户的工作空间独立开来, 并使其有利与并行开发.这个工具属于Open Source, ,CVS可以在intenet 上很方便的得到. 它的源码在ftp://202.113.29.4/pub1/unix/cvs 它的说明文档在ftp://202.113.29.4/doc/cvs.任何人可以很方便的下载.目前他的最新版本是2..10.8。 不需要花钱,很快建立,重点在于使用和推广。配合项目经理共同制定相应的配置管理策略,取得了很好的成效。
    2.2.1. 节约费用
    (1) 缩短开发周期
    利用CVS对程序资源进行版本管理和跟踪,建立公司的代码知识库,保存开发过程中每一过程版本,这样大大提高了代码的重用率,还便于同时维护多个版本和进行新版本的开发,防止系统崩溃,最大限度地共享代码。同时项目管理人员可以通过Version 系统查看项目开发日志,测试人员可以根据开发日志和不同版本对软件进行测试,工程人员可以从版本控制系统上得到不同的运行版本,并且可以安装在Web Server或在Unix操作系统上命令行方式存取供外地施工人员存取最新版本,无需开发人员亲临现场。
    利用CVS系统,可以大大提高开发效率,避免了代码覆盖、沟通不够、开发无序的混乱局面,如果利用了公司原有的知识库,则更能提高工作效率,缩短开发周期。
    (2) 减少施工费用
    利用CVS进行软件配置管理后,建立开发管理规范,把版本管理档案挂接在公司内部的Web服务器上,工程人员可以通过远程进入内部网,获取所需的最新版本。开发人员无需下现场,现场工程人员通过对方系统管理员收集反馈意见,书面提交到公司内部开发组项目经理,开发组内部讨论决定是否修改,并作出书面答复。这样做,可以同时响应多个项目点,防止开发人员分配到各个项目点、分散力量、人员不够的毛病,同时节约大量的旅差费用。
    2.2.2. 有利于知识库的建立
    (1) 代码对象库
    软件代码是软件开发人员脑力劳动的结晶,也是软件公司的宝贵财富,长期开发过程中形成的各种代码对象就像一个个零件坯一样,是快速生成系统的组成部分。长期的一个事实是:一旦某个开发人员离开工作岗位,其原来所作的代码便基本成为垃圾,无人过问。究其原因,就是没有专门对各人的有用对象进行管理,把其使用范围扩大到公司一级,进行规范化,加以说明和普及。CVS系统为开发管理提供了一个平台和仓库,有利于建立公司级的代码对象库。
    (2) 业务及经验库
    通过CVS的注释,可形成完整的开发日志及问题集合,以文字方式伴随开发的整个过程,不依某个人的转移而消失,有利于公司积累业务经验,无论对版本整改或版本升级,都具有重要的指导作用。
    2.2.3. 规范管理
    (1) 量化工作量考核
    传统的开发管理中,工作量一直是难以估量的指标,靠开发人员自已把握,随意性相当大;靠管理人员把握,主观性又太强。采用CVS管理后,开发人员每天下班前对修改的文件 Check In,其中记述当天修改细节描述,这些描述可以作为工作量的衡量指标。
    (2) 规范测试
    采用CVS以后,测试有了实实在在的工作,测试工作人员根据每天的修改细节描述对每一天的工作做具体的测试,对测试人员也具有可考核性,这样环环相扣,大大减少了其工作的随意性。
    (3) 加强协调与沟通
    采用CVS后,通过VSS文档共享系统和 Bugzilla缺陷跟踪系统,大大加强了项目成员之间的沟通,做到有问题及时发现、及时修改、及时通知,但又不额外增加很多的工作量。
    3.性能测试是软件测试专业化的核心所在
    从华友实践看,软件测试对于产品经理、开发经理和市场经理都有所认识,他们大部分人会认为功能测试工作他们能够很好的完成,产品经理是公司对于业务最熟悉的 一批人,他们对于测试工程师最急切的需求是你帮我实施产品的性能测试工作,他们听说过性能测试,我们的产品投入在线运行后碰到的最大故障是大用户量访问业务是机器凼机,或停止正常的服务,每次故障,几乎给公司的收入都造成很大损失。如果测试部门能有一套有效的性能测试手段,就确立了测试部门在项目开发过程中关键地位。
    性能测试在华友软件的质量保证中起着非常重要的作用,将性能测试概括为四个方面:Wap无线应用服务在手机用户端性能测试、 Web/Wap应用服务在客户端性能的测试、应用在网络上性能的测试和应用在服务器端性能的测试。通常情况下, 四方面有效、合理的结合,可以达到对系统性能全面的分析和瓶颈的预测。
    3.1 Wap无线应用服务在手机用户端性能测试
    如今人人用手机都追求时尚,时尚体现在款式, 品牌和功能。手机产品功能的日新月异,移动增值业务功能层出不穷,从最初的短信、彩信、铃声到GPRS,CDMA,K-Java, Brew手机,功能的多样性带来手机用户端软件系统测试的复杂性。众所周知, Java手机吸引人之处是能提供智能的, 个人化的互动服务, 例如: 动态产生个人化的股市服务, 显示图形, 动画, 实时路况, 气象报告, 数字照像, 玩游戏等, 部分服务能直接于用户端执行。
    为了提供如此生动的服务, 移动通信系统要能给终端用户在无线装置上提供接入互联网的功能, 要能储存、提取、管理、计算、结帐、下载软件服务, 并使内容提供商能提供丰富的声像多媒体内容, 形成广大的个人化交互式服务环境。 而作为移动用户, 可将手机视作虚拟机, 能随时、随地在适当的装置上存取应用, 享受服务。 这确是一种时尚。
    当前, 对于不同品牌的手机, 它们所用的平台(指CPU和操作系统)各不相同, 由于采用不同的设计方案, 各设计之间缺乏兼容性, 操作系统和二进制代码都不兼容。 当手机运行需要大量内存时, 特别是随着接入互联网, 手机用户要求能使用个性化的 交互式应用软件, 应用程序运行在虚拟运行环境下时, 问题显得尤为突出。 所以, 有必要建立一种标准的通用运行平台, 达到在合适的成本下提供统一的交互式应用软件运行环境。 但是, 除非该平台是基于完全标准的器件, 否则是难以达到要求的。
    标准的通用的运行平台是满足运营商, 软件开发商, 和终端用户三者综合要求的解决办法。 理想的环境必须具备以下性质:
    (1)、平台应提供二进制兼容性。 可执行软件是二进制目标码, 需要在处理器和应用软件目标码之间建立沟通;
    (2)、平台必须包括微处理器,或一个与微处理器机器代码相离的通用机器码仿真器;
    (3)、平台应包括带有应用程序接口API及支持一致性图形用户界面GUI相应功能的操作系统。 API 是执行典型操作功能的软件功能库, 例如打开文件, 读写数据, 配置和管理内存, 处理事件, 显示文档和图形等。 为使应用软件真正做到可移植, 装置上必须有公共功能集, 并让软件开发者能通过一致性API 扩展功能;
    (4)、平台不应要求过多的系统资源, 可移植性设备不应使成本上升太多;
    (5)、平台应对功率有高效率, 尤其考虑用电池供电的设备;
    (6)、由于要在互联网上应用, 安全性也是重要因素。
    以Java手机软件测试为例潜在的测试问题和解决办法
    Java有移植性好和其它很多优势, 但用在手机上, 速率和功耗仍是个瓶颈。 Java带来的新问题是执行速度慢, 消耗功率大。 与PC不同的是, 手机资源有限, 一般流行的手机中CPU的速率为26MHz, 或52MHz,带128M闪存, 8Mb, 16M 或64Mb内存, 没有硬盘, 由电池供电, 体积小, 空间窄。 系统慢的原因是:
    (1) 系统必须同时运行两套软件: Java应用和虚拟机JVM;
    (2) Java软件需要被翻译成自然CPU指令;
    (3) Java平台是基于栈(相对于寄存器)结构的, 导致更多的内存存取。
    因而, 如何对执行 Java加速成为关键。 加速处理数据和图形, 这对手机上互联网和多媒体的应用具有重要意义。 要克服这些问题, 提高Java软件性能, 可能的方法有四种:
    (1) 提高微处理器速率。 然而Java软件性能与时钟频率并不成线性关系, 微处理器运行一般比内存存取时间高2-10倍, 增加时钟频率只会增加等待周期。
    (2) 对JVM软件进行优化。 这可能涉及到要用汇编语言对字节码翻译环路进行编程, 而这会导致JRE变得与微处理器类别有关。 而与可移植相抵触;
    (3) 编译。 将软件直接编译到微处理器的自然机器语言。 但是这会增加内存的开销, 也不节省能量的消耗。
    (4) 采用基于硬件的加速器。 这可以做到提高性能, 保障能量和成本的有效性。 被手机设计厂商认为是较理想的措施。 通用型Java加速芯片于今年年初问世。
    3.2 分析Web/Wap应用服务在客户端性能的测试
    Web/Wap应用服务在客户端性能测试的目的是考察客户端应用的性能,测试的入口是客户端。它主要包括并发性能测试、大数据量测试和速度测试等,其中并发性能测试是重点。
    并发性能测试的过程是一个负载测试和压力测试的过程,即逐渐增加负载,直到系统的瓶颈或者不能接收的性能点,通过综合分析交易执行指标和资源监控指标来确定系统并发性能的过程。负载测试(Load Testing)是确定在各种工作负载下系统的性能,目标是测试当负载逐渐增加时,系统组成部分的相应输出项,例如通过量、响应时间、CPU负载、内存使用等来决定系统的性能。负载测试是一个分析软件应用程序和支撑架构、模拟真实环境的使用,从而来确定能够接收的性能过程。压力测试(Stress Testing)是通过确定一个系统的瓶颈或者不能接收的性能点,来获得系统能提供的最大服务级别的测试。
    并发性能测试的目的主要体现在三个方面:以真实的业务为依据,选择有代表性的、关键的业务操作设计测试案例,以评价系统的当前性能;当扩展应用程序的功能或者新的应用程序将要被部署时,负载测试会帮助确定系统是否还能够处理期望的用户负载,以预测系统的未来性能;通过模拟成百上千个用户,重复执行和运行测试,可以确认性能瓶颈并优化和调整应用,目的在于寻找到瓶颈问题。
    我们公司自己组织力量同时委托第三方软件HG公司开发Hawa网站的一套应用Avatar形象系统的时候, Avatar形象在网站业务中占有着重要的位置,网站上的很多业务都是围绕Avatar开展。 这套系统能不能承受大量的并发用户同时访问? 成为这个网站能否成功的关键,也是这次两个公司合做开发能否顺利完成的关键。这类问题最常见于采用联机事务处理(OLTP)方式数据库应用、Web浏览和视频点播等系统。这种问题的解决要借助于科学的软件测试手段和先进的测试工具。
    Web软件测试实例说明:哈哇网站Avatar形象系统软件。Avatar形象系统在上线试运行三个月后,所有的功能测试顺利完成,软件功能缺陷也修改完毕。但是,性能问题越来越成为项目经理关心的焦点,我们测试部门借助比较熟悉的压力测试工具Web Stress 实施客户端性能测试进行100,500,1000等并发用户访问。每次测试主要在基于URL:http://avatar.hawa.cn/index.jsp的基础上,与HG公司实时交互地进行多种情况下的测试。按照HG公司要求主要针对并发数为1000和500的情况下,尽量准确的对Avatar系统的性能压力进行模拟测试;并排除所有不是从web服务器(即avatar.hawa.cn)上得到的URL,即只对/index.jsp等页面进行测试。三次结果后,尽管程序优化、运行服务器配置多次修改,仍然存在用户量并发数达到1000,服务质量下降,页面方面时间超过正常显示时间。这里有最后一次测试结果与前几次大致相同。但是本次测试,是用多客户端测试,按原理是应该比以前的单机测试准确度要高,但其结果是比用单机测试的时间还要长,当并发数达到1000时,其页面的最长响应时间在80多秒(而单机测试时时59秒多)!第三次又发现ISP网络100MB带宽实际上不到20MB,也是影响用户服务的关键因素之一。
    这个性能问题经过HG公司开发人员近三个月改进,/index.jsp页面的1000个用户并发响应时间10秒左右。对于我方采用的Web Stress性能测试工具HG公司也认同其测试结果的客观性,公司因为该软件性能问题推迟支付对方经费200万圆三个月,更重要的是软件的性能问题得到很好解决,并与HG公司的关系很好保持。另外一个更大的收获是测试部门在Web 产品部门有个很好的形象,他们每次新软件产品需求提出、产品上线都主动要求测试部门参与并实施严格测试。
    如何模拟实际情况呢? 找若干台电脑和同样数目的操作人员在同一时刻进行操作,然后拿秒表记录下反应时间? 这样的手工作坊式的测试方法不切实际,且无法捕捉程序内部变化情况,这样就需要压力测试工具的辅助。
    测试的基本策略是自动负载测试,通过在一台或几台PC机上模拟成百或上千的虚拟用户同时执行业务的情景,对应用程序进行测试,同时记录下每一事务处理的时间、中间件服务器峰值数据、数据库状态等。通过可重复的、真实的测试能够彻底地度量应用的可扩展性和性能,确定问题所在以及优化系统性能。预先知道了系统的承受力,就为最终用户规划整个运行环境的配置提供了有力的依据。
    并发性能测试前的准备工作
      
    测试环境:配置测试环境是测试实施的一个重要阶段,测试环境的适合与否会严重影响测试结果的真实性和正确性。测试环境包括硬件环境和软件环境,硬件环境指测试必需的服务器、客户端、网络连接设备以及打印机/扫描仪等辅助硬件设备所构成的环境;软件环境指被测软件运行时的操作系统、数据库及其他应用软件构成的环境。
      
    一个充分准备好的测试环境有三个优点:一个稳定、可重复的测试环境,能够保证测试结果的正确;保证达到测试执行的技术需求;保证得到正确的、可重复的以及易理解的测试结果。
      
    测试工具:成熟的并发性能测试工具有很多,选择的依据主要是测试需求和性能价格比。著名的并发性能测试工具有QALoad、LoadRunner、Benchmark Factory、 Webstress和AB-Apache等。这些测试工具都是自动化负载测试工具,通过可重复的、真实的测试,能够彻底地度量应用的可扩展性和性能,可以在整个开发生命周期、跨越多种平台、自动执行测试任务,可以模拟成百上千的用户并发执行关键业务而完成对应用程序的测试。
      
    测试数据:在初始的测试环境中需要输入一些适当的测试数据,目的是识别数据状态并且验证用于测试的测试案例,在正式的测试开始以前对测试案例进行调试,将正式测试开始时的错误降到最低。在测试进行到关键过程环节时,非常有必要进行数据状态的备份。制造初始数据意味着将合适的数据存储下来,需要的时候恢复它,初始数据提供了一个基线用来评估测试执行的结果。
      
    在测试正式执行时,还需要准备业务测试数据,比如测试并发查询业务,那么要求对应的数据库和表中有相当的数据量以及数据的种类应能覆盖全部业务。
    模拟真实环境测试,有些软件,特别是面向大众的商品化软件,在测试时常常需要考察在真实环境中的表现。如测试杀毒软件的扫描速度时,硬盘上布置的不同类型文件的比例要尽量接近真实环境,这样测试出来的数据才有实际意义。
      
    并发性能测试的关键的是测试过程中对监控对象的灵活应用,例如目前三层结构的运行模式广泛使用,对中间件的并发性能测试作为问题被提到议事日程上来,许多系统都采用了国产中间件,选择Java scrīpt监控对象,手工编写脚本,可以达到测试目的。
      
    采用自动化负载测试工具执行的并发性能测试,基本遵循的测试过程有:测试需求与测试内容,测试案例制定,测试环境准备,测试脚本录制、编写与调试,脚本分配、回放配置与加载策略,测试执行跟踪,结果分析与定位问题所在,测试报告与测试评估。
      
    3.3 应用在网络上性能的测试
    应用在网络上性能的测试重点是利用成熟先进的自动化技术进行网络应用性能监控、网络应用性能分析和网络预测。
      
    网络应用性能分析
      
    网络应用性能分析的目的是准确展示网络带宽、延迟、负载和TCP端口的变化是如何影响用户的响应时间的。利用网络应用性能分析工具,例如Application Expert,能够发现应用的瓶颈,我们可知应用在网络上运行时在每个阶段发生的应用行为,在应用线程级分析应用的问题。可以解决多种问题:客户端是否对数据库服务器运行了不必要的请求?当服务器从客户端接受了一个查询,应用服务器是否花费了不可接受的时间联系数据库服务器?在投产前预测应用的响应时间;利用Application Expert调整应用在广域网上的性能;Application Expert能够让你快速、容易地仿真应用性能,根据最终用户在不同网络配置环境下的响应时间,用户可以根据自己的条件决定应用投产的网络环境。
      
    网络应用性能监控
      
    在系统试运行之后,需要及时准确地了解网络上正在发生什么事情;什么应用在运行,如何运行;多少PC正在访问LAN或WAN;哪些应用程序导致系统瓶颈或资源竞争,这时网络应用性能监控以及网络资源管理对系统的正常稳定运行是非常关键的。利用网络应用性能监控工具,可以达到事半功倍的效果,在这方面我们可以提供的工具是Network Vantage。通俗地讲,它主要用来分析关键应用程序的性能,定位问题的根源是在客户端、服务器、应用程序还是网络。在大多数情况下用户较关心的问题还有哪些应用程序占用大量带宽,哪些用户产生了最大的网络流量,这个工具同样能满足要求。
      
    网络预测
      
    考虑到系统未来发展的扩展性,预测网络流量的变化、网络结构的变化对用户系统的影响非常重要。根据规划数据进行预测并及时提供网络性能预测数据。我们利用网络预测分析容量规划工具PREDICTOR可以作到:设置服务水平、完成日网络容量规划、离线测试网络、网络失效和容量极限分析、完成日常故障诊断、预测网络设备迁移和网络设备升级对整个网络的影响。
      
    从网络管理软件获取网络拓扑结构、从现有的流量监控软件获取流量信息(若没有这类软件可人工生成流量数据),这样可以得到现有网络的基本结构。在基本结构的基础上,可根据网络结构的变化、网络流量的变化生成报告和图表,说明这些变化是如何影响网络性能的。 PREDICTOR提供如下信息:根据预测的结果帮助用户及时升级网络,避免因关键设备超过利用阀值导致系统性能下降;哪个网络设备需要升级,这样可减少网络延迟、避免网络瓶颈;根据预测的结果避免不必要的网络升级。
    3.4 应用在服务器上性能的测试
      
    首先分析服务器的类型,服务器的划分起码可以依据四大部分进行。一是根据整个架构,可分为IA服务器和RISC服务器;二是按照硬件配置的差别可分为工作组级、部门级、企业级;三是按照具体安装的应用软件可分为Web服务器、文件服务器、FTP服务器、E-mail服务器、数据库服务器等等;四是根据操作系统分为WINDOWS阵营、UNIX阵营。这四大分类有所关联,但其中按应用分类是最能给用户清晰概念的。因为用户在采购选型时,总是先想好了拿它做什么用的。Intel最近所提出的前端(用于接入等)、中端(用于各种应用和中间件)和后端(用于数据库、在线分析等)的分类办法,这也是从应用角度考虑的。
    分析服务器性能指标莫不聚焦于三大指标:CPU、I/O及Web。如果大家还记得图灵机的话,应该对计算单元和输入输出的重要不会抱什么怀疑的态度。至于选择Web作为衡量服务器性能的要点,只能说是网络的力量。Internet的大行其道让我们很难想象有服务器孤岛出现。工程师往往通过给与被测服务器不断增加的并发式文件读写、数据库操作以及HTTP访问来取得其最大的潜值。
    以Web测试为例,衡量Web性能一般有下列几个重要指标:HTTP 每秒交易数(Transaction Per Second);每秒会话数(Sessions Per Second);当前用户数(Concurrent users);吞吐量(Throughput)。HTTP TPS通常也叫做每秒的点击数;每秒会话数是每秒到达Web服务器的用户数;当前用户数是特定时间在Web 站点上的用户数;吞吐量是在特定时间由Web站点发出的数据流量带宽,它与服务器提供服务的内容和交易数相关。以上将是我们对测试结果进行评述与点评的重要技术基础。
    4.项目管理开发环节的测试任务
    当公司构架了合理的组织结构并制定了缜密的计划后,就进入了产品的开发阶段。 下面以已经实施完成的CYB项目一期为例,分析华友公司在项目管理上的正在推广的具体 项目管理细节的优缺点和测试工作改进探讨:
    CYB项目一期需求:由于华友各类业务(SMS和WAP等)在不同运营商(中国联通、中国移动、中国电信等)的不同平台和在网站www.hawa.cn 的WEB门户中向用户提供服务,各类业务的相互独立,为了统一管理用户信息、业务和计费等信息,并汇总进行统计分析处理,同时也为了整合各类业务系统的资源,建立公司的业务运营支撑系统。
    4.1 开发阶段和项目周期
    开发阶段比较明显,注重各阶段应完成的功能,对本阶段应完成的工作不能留到下一阶段。明确项目经理为D,项目组开发程序员六人,项目第一阶段周期3个月,项目需要完成的功能:
    1)实现用户信息的统一管理,包括:用户基本信息,用户使用业务的积分,用户的定制/退定信息的管理
    2)实现各类业务信息的集中管理,包括:短信业务、WAP1.2、WAP2.0、JAVA、彩铃等各种业务
    3)实现计费信息的统一管理
    4)提供客服功能
    5)提供统计分析功能
    6)提供统一的标准接口,分别与各业务子系统及运营商的系统相连接
    7)提供网络管理、监控等功能
    在这个阶段,测试经理需要负责详细了解项目开发需要的需求、设计文档等,制订初步的测试方案,根据测试任务的特点决定测试开发任务。实际结果表明开发阶段的最大两个问题:重视设计、不重视测试和软件质量,设计会议开了至少五次,参加会议有公司很有经验的设计人员,测试有关人员没有被邀请参加,忽视产品的性能需求,更多的关注基本功能实现;忽视需求是客服和运维人员,自以为很理解市场部提出的需求,忽视程序开发人员实现的难度和开发人员之间理解需求的差别,项目组成员之间重视口头交流,忽视文档价值。
    问题解决方法:开始阶段请测试和质量保证工程师参加讨论,就会提出软件实现的性能需求;重视文档交流的价值,建立软件文档模版和版本控制机制,每次交流落实在成员理解和书面文档。
    4.2 软件开发流程
    华友公司原来是重视项目管理,忽视流程,一味夸大个别人努力在项目成功中的作用。经过一年痛苦的实践,开始探讨流程管理,已经启动公司的SW-CMM质量体系认证工作,希望建立非常规范化和系统化的软件开发流程,其流程的有很高的可执行性,并且能在实践过程中不断改进。华友公司的流程管理改进从一个项目研发的所有方面开始摸索,包括从最开始的意向、市场策划到最后软件的版本发布(release)上线投入商业运营,都设计有相应的流程规定,基本上已由测试部门负责推广一种能够达到规范、高效的软件开发流程。
    CYB项目经理D重视口头交流沟通,忽视文档交流,同时缺少与项目组成员知识共享意识;经理D重视与领导的交流,忽视与开发人员交流,项目实施中开发人员碰到具体问题没人协助解决,开发效率降低。虽然流程没错,但是流程涉及到开发人员出现问题也是需要重视的。流程管理的关键,以"人"为本。
    目前的组织框架下,经过一年多的工作实践,深深体会到人和流程是保证项目成功的两个最关键因素。由具备项目实施基本素质的人按规范的合理化流程进行项目开发,才能最大限度地保证项目的成功。一个好的流程可以保证差一点的人做出来的东西不至于太差,但不能确保做出精品。通过流程可以实现一种规范化、流水线化、工业化的软件开发。通过流程我们部门间的配合才节省宝贵时间,为项目早期完成,赢得市场主动权。
    4.3 项目计划的阶段性
    1) 努力做到项目计划详细、周到。CYB项目计划从开始有三个月计划,到修改三次以上,计划完成时间从三个月、延长到六个月、直到现在的八个月。计划已经形同虚设。实践证明不合理的计划不如没有计划,不合理的计划给领导造成错误的认识。合理的计划应该是先明确本周工作计划,对于难以预测的任务或者困难给出一个近期工作的方向,然后根据实际进展情况进行细化调整。
    2) 流程中明确定义开发阶段、测试阶段。开发阶段任务没有完成,占用测试阶段计划时间,测试工作效率降低。正确的处理方式建议不要减少测试工作时间,项目开发完成时间根据实际需要顺延。
    3) 每个阶段都列出了该阶段的各项活动,并详细描述每项活动的属性:
    进入条件,输入;
    验证方法;
    结束条件,输出。
    4) 每个阶段结束都要召开阶段结束会议。前一个阶段结束(以本阶段开发任务测试完成为标志)才能进入下一阶段。项目经理需要在每个阶段测试任务完成情况进行分析,存在的问题要充分暴露出来,以便于早点解决。 CYB项目经理D采取报喜不报优的做法,在会议上常得到领导的表扬,其他项目经理常愁眉苦脸摆出人员问题、可能的技术问题、测试人员和时间问题等。实际结果最后笑的项目经理也是项目完成比较顺利。
    5) 理想计划中每个活动都比较具体,每个活动的时间以天为单位。计划包括了开展质量控制活动的时间,推广说明版本控制系统和缺陷跟踪系统的使用的时间。
    典型案例是公司研发用于用户信息管理的代号CYB项目,CYB项目开始时副总裁牵头,由于测试人员少没有参与,开发经理们讨论设计实施方案后几乎大家一片赞美。随后项目经理D负责开发,他认为时间紧,省去了许多必须的文档工作。经理D采取报喜不报优的做法,项目文档差,过分强调计划,而忽视计划任务达到的质量,大部分项目测试没有完成就宣布开发完成,结果前三个月每次经理会上总裁都会表扬他们取得的阶段成果,我做为测试经理没有说话的机会,有一次刚讲几句,总裁马上提醒希望大家克服困难,每个组的任务都可能需要加班等。结果原计划三个月完成项目,已经过了半年发现要实现商用还需要做很多工作,具体完成时间也不确定, 可是现在每天总是强调专人测试,问文档没有,只能通过问了一次又一次的沟通方式实施测试工作, 有个不错的测试人员实在无法忍耐,辞职了,我只好安排新的测试人员应对完成任务。这个CYB项目遭到了整个公司的一片嘘声,虽然没有放弃,但没有商业价值了。快9个月的研发成本老本最清楚去那儿了。
    总结教训,项目经理对计划和测试工作的高度重视、周密制定、严格执行是能够实现项目有效商业价值的基本保障。
    4.4 重视Review的作用
    按软件工程规范化流程,一般把Review和测试作为保证软件质量两个主要手段。测试的重要性已经成为各项目经理认识,并贯穿于开发的全过程,形成了项目组成员人人重视测试工作的氛围。Review则是一个非常简单有效并能尽早发现软件中错误的有效方法,项目经理在每周必须根据进展情况制订Review计划,可以说,任何交付物都要经技术总监参加的Review后才能进行基线化。目前华友公司正在建立比较详细全面、可执行性高的由Review流程和各种交付物的Review Checklist。
    我们正在弥补这方面的工作流程缺陷,提出:凡事有计划,凡事必review。首先在开发组内部推广代码规范化工作,定期进行员工Code Review的工作, Code Review 是工作的重要环节。
    4.5 质量管理和测试(QA)
    公司目前没有独立的质量管理部门,暂时由测试部门测试经理作为质量保证部门的代表,监督和保证项目的进展的各项流程和模板,并且收集项目中发现的一些问题和解决方法以优化流程。由于公司对测试人才有着迫切的需要,因此,只好自己组建培养测试人才队伍。从现实出发,我们不可能想IBM和微软等大公司有雄厚的才力支持质量保障和测试工作开展,我们的工作重点放在软件测试方面。从起步三人开始的实施测试工作,首先测试工程师的工作让项目经理和上级领导发现并肯定他们的工作成果。通过对比测试人员实施测试后的模块和未实施测试的模块投入商业运营带来的很大差异,看到软件修补的高昂费用,提高了领导和项目经理对测试部门的重视程度。逐步扩大测试人员数量,增加测试队伍的规模,提高测试人员的的福利待遇成为可能。
    招聘测试人员时,要把好质量关,国内联想、华为等公司一般对于测试人员待遇底,重视不够,我们需要测试认为改变这种错误认识,让优秀的人加入测试队伍。目前测试部门工程师10个人中有2个留学回国计算机方面硕士,其余几人都是计算机或相关学科本科生。尽管经验方面不够,但测试人员的素质和专业技能是国内一流的,一段时间测试团队的努力,这个部门已经成为公司业务开发的至关重要的部门。要不断提高软件测试的自动化程度,测试工作不能仅靠手工劳动来完成,更多的情况是要使用工具软件和编写测试程序来完成,培养全面的测试专业人才是项任重道远的工作。
    4.6 度量数据
    公司最近开始CMM的质量管理体系工作,CMM中比较强调用数据说话,对项目过程中基本上所有的数据都会有记录,最后把收集的数据提交质量保证部门进行分析,以改进流程。但是公司的项目管理定量化工作实施有一定难度,配合华友公司的绩效考核,测试部门要求项目经理重视项目中的数据收集,主要包括各种Review数据、测试数据以及项目组员每天的活动数据等。要求项目经理也要维护一个项目档案,在这个项目档案中可以说包含了项目开发过程中所有的产出、开发活动、管理活动等的记录。测试部门提供能够进行团队项目开发的CVS或VSS等团队开发系统,可以这么说,有了这个项目团队开发系统,测试经理和项目经理就可以方便了解这个项目的开发过程。
    4.7 团队精神
    团队精神就好比人身体的每个部位,一起合作去完成一个动作。对公司来讲,团队精神就是每个人各就各位,通力合作。我们公司的每一个奖励活动或者我们的业绩评估,都是把个人能力和团队精神作为两个最主要的评估标准。如果一个人的能力非常好,而他却不具备团队精神,那么我们宁可选择后者。公司强调团队精神、合作精神,应该说,其流程本质上就要求员工之间的互相协调和理解。公司不定期的对经理级别人员进行团队管理培训,在对员工不断进行相关培训,使员工的合作精神和协调精神都比刚进入公司时有较大提高。
    4.8 培训
    公司有专门的培训人员和培训费用计划,每半年会征集员工培训需求和建议,然后安排有关主题的培训活动。在新员工进入公司后都会有公司流程和其他一些公司普遍章程的培训,以保证员工对流程的理解和执行。对于具体项目,项目经理在制定项目计划时就会在项目计划中提出所有的培训需求,包括技术上的培训和其他所需的培训。
    4.9 配置管理
    在项目正式开展前,项目经理就要制定配置管理计划,并且指定配置管理员建立起配置管理库,按配置流程严格进行配置管理。在配置流程中也详细提供了对更改的控制,没有经过批准的更改请求是绝对不能进行的。
    4.10 记录
    记录及时、充分、比较准确。这些记录包括:重要的邮件、会议纪要、审核记录、缺陷报告、测试报告。
    1)提倡与客户和其他项目组的所有往来必须邮件记录。
    2)对所有的活动都有一个跟踪落实的过程,比如对所有的Review记录和更改请求都会有一个状态标识,标识其当前状态,通过跟踪其状态来监督其落实。
    3)对所有的活动,包括对文档和代码的更改都会有一个历史记录。
    4)记录比较准确、比较客观。
    以上是华友公司在项目管理中所涉及到的一些主要环节,很值得国内的软件企业在制定项目管理规划时借鉴。


    谈项目管理和软件测试过程(二)  
        
       2004-11-19 11:48:13 
      
     
     
      雷红旗  
      2.配置管理系统是项目经理的"眼睛",是软件测试有效实施的前提

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

    2.1 项目管理存在的主要问题
    华友公司测试部门去年刚成立时,以建立、规范和推广使用配置管理系统CVS为突破口,同时建立缺陷跟踪系统Bugzilla提高测试流程的管理水平。我做为测试负责人首先分析华友公司几个软件项目在开发管理上的现状,。

    存在问题一、公司几个核心项目仍然过分分依赖少数个人的作用,没有建立起协同作战的氛围,没有科学的软件配置管理流程; 技术上只重视系统和数据库、开发工具的选择,而忽视配置管理工具的选择,导致即使有些项目有配置管理的规程,也由于可操作性差而搁浅。以上种种原因导致开发过程中普遍存在如下一些问题: 调查说明华友研发成员的变动的比率达到30%,几乎每周都有新加入的员工或者辞职人员, 一个新成员熟悉项目的最佳途径就是通过配置管理系统阅读项目文档,甚至阅读同行代码,达到快速学习、共同提高的目的。一个辞职人员可以利用配置管理系统保留部分一段时间工作,最大程度减少对项目开发造成的损失。

    存在问题二、开发管理松散。领导了解工作完成情况重视口头交流,忽视书面文档。有些部门主管无法确切得知项目的进展情况,项目经理也不知道各开发人员的具体工作,项目进展随意性很大,可"左"可"右"。"左"时按领导下达的"期限"进行,到期时,似乎一切已顺利完成,大家一阵胡弄,交差完成,反正领导看的是界面,至于里面是什么,留到施工时再说。施工时的工作因此变成了无法汇报、无法理清的无休止的维护。"右"时则项目工期无休止地延期。对我们软件工程来说,总的特点是先"左"后"右"。在领导面前表现"左",在用户面前表现"右"。有个测试人员经常利用上班时间学习英语,过了一个多月,看她依然如此,我做为项目领导进行批评教育,这名员工并不认为自己错了,她争辩,公司采取弹性工作时间,考核员工是分配的任务是否完成等理由。同时、我对她批评结果遭到她的恶意报复,她给有关领导报告新来的经理如何不懂公司业务,采取不适合公司的管理方式等,由于领导无法了解真相,使得我的工作在一段时间开展很困难,直到过去半年,这名员工辞职出国学习领导才明白发生了什么。 

    存在问题三、项目之间沟通不够。各个开发人员各自为政,每个项目经理都像个"地主",编写的代码不仅风格各异,而且编码和设计脱节。每个项目组的人力资源和硬件资源成了"私有财产",自己人员即使暂时空闲,让他从事所谓的新技术研究,也不考虑友邻项目需要他们帮助的现状。本来开发中错误在所难免, 进展早一点的项目组或者人力资源强的项目组已经积累类似问题的解决经验,也不愿意分享给其它项目组。 开发大量重复, 留下大量难维护的代码。典型案例是有个短信项目D两年来在这个开发人员Y 的研发支持下运转效益很好,但是三个月之前,开发人员 Y因为待遇问题和公司领导谈判失败,提出辞职。项目D仍然在运行,但是最近移动公司规范修改、系统升级,需要修改程序,没人能看到及时更新的文档,尽管有一堆代码库,但是后来的程序员都没办法分析明白程序结构。公司领导出面请开发人员Y来协助,因为没有文档记录,Y忙于新公司的工作也不能解决修改。

    存在问题四、文档与程序严重脱节。软件产品是公司的宝贵财富,代码的重用率是相当高的,如何建好知识库,用好知识库对公司优质高效开发产品,具有重大的影响。但开发人员的一句名口号是:"叫我干什么都可以,但别叫我看别人的程序"。当然,开发人员的工作态度要转变,但客观上有一个很重要的原因是:前人留下的程序既无像样的文档(即使留下了文档 ,其与源程序也严重脱节),开发风格又不统一,就像一堆垃圾,要开发人员到垃圾中去捡破烂,从这个角度上看,开发人员的要求是合理的。 

    存在问题五、测试工作不规范。仍然停留在"小姑娘做测试"的底水平上,传统的开发方式中,测试工作只是人们的一种主观愿望,根本无法提出具体的测试要求,加之开发人员的遮丑,测试工作往往是走一走过场,测试结果既无法考核又无法量化,当然就无法对以后的开发工作起指导作用。 

    存在问题六、虽然项目施工时间不长,但软件版本更新周期过短,几乎每天都修改在线运行系统,且开发人员必须亲自现场或远程登陆操作,全国十几个地点软件内容多少都有点差别,这些差别都记录在几个骨干人物的脑袋里。 由于应用软件的特点,各个不同的施工点有不同的要求,开发人员要手工地保持多份不同的拷贝,即使是相同的问题,但由于在不同地方提出,由不同人解决,其做法也不同,程序的可维护性越来越差。久而久之,最后连自已都分不清楚了,代码的相互覆盖现象时有发生,且这苦水还无法倾诉,因为怕别人笑话,甚至别人问起,还得想法搪塞,可谓费尽苦心。 

    2.2 建立配置管理系统,规范项目管理流程,建立知识库的同时节约项目费用

    针对以上问题, 利用自己在Beijing Precom Inc, 普天润汇等公司积累的经验,建立配置管理系统CVS, CVS 的全称是Current Version Control. CVS是一种GNU 软件包.由Intersolv公司开发,它明确的将源文件的存储和用户的工作空间独立开来, 并使其有利与并行开发.这个工具属于Open Source, ,CVS可以在intenet 上很方便的得到. 它的源码在ftp://202.113.29.4/pub1/unix/cvs 它的说明文档在ftp://202.113.29.4/doc/cvs.任何人可以很方便的下载.目前他的最新版本是2..10.8。 不需要花钱,很快建立,重点在于使用和推广。配合项目经理共同制定相应的配置管理策略,取得了很好的成效。 

    2.2.1. 节约费用 

    (1) 缩短开发周期 

    利用CVS对程序资源进行版本管理和跟踪,建立公司的代码知识库,保存开发过程中每一过程版本,这样大大提高了代码的重用率,还便于同时维护多个版本和进行新版本的开发,防止系统崩溃,最大限度地共享代码。同时项目管理人员可以通过Version 系统查看项目开发日志,测试人员可以根据开发日志和不同版本对软件进行测试,工程人员可以从版本控制系统上得到不同的运行版本,并且可以安装在Web Server或在Unix操作系统上命令行方式存取供外地施工人员存取最新版本,无需开发人员亲临现场。 
       
    利用CVS系统,可以大大提高开发效率,避免了代码覆盖、沟通不够、开发无序的混乱局面,如果利用了公司原有的知识库,则更能提高工作效率,缩短开发周期。 

    (2) 减少施工费用 
       
    利用CVS进行软件配置管理后,建立开发管理规范,把版本管理档案挂接在公司内部的Web服务器上,工程人员可以通过远程进入内部网,获取所需的最新版本。开发人员无需下现场,现场工程人员通过对方系统管理员收集反馈意见,书面提交到公司内部开发组项目经理,开发组内部讨论决定是否修改,并作出书面答复。这样做,可以同时响应多个项目点,防止开发人员分配到各个项目点、分散力量、人员不够的毛病,同时节约大量的旅差费用。
     
    2.2.2. 有利于知识库的建立 

    (1) 代码对象库 
       
    软件代码是软件开发人员脑力劳动的结晶,也是软件公司的宝贵财富,长期开发过程中形成的各种代码对象就像一个个零件坯一样,是快速生成系统的组成部分。长期的一个事实是:一旦某个开发人员离开工作岗位,其原来所作的代码便基本成为垃圾,无人过问。究其原因,就是没有专门对各人的有用对象进行管理,把其使用范围扩大到公司一级,进行规范化,加以说明和普及。CVS系统为开发管理提供了一个平台和仓库,有利于建立公司级的代码对象库。 

    (2) 业务及经验库 

    通过CVS的注释,可形成完整的开发日志及问题集合,以文字方式伴随开发的整个过程,不依某个人的转移而消失,有利于公司积累业务经验,无论对版本整改或版本升级,都具有重要的指导作用。 

    2.2.3. 规范管理 

    (1) 量化工作量考核 

    传统的开发管理中,工作量一直是难以估量的指标,靠开发人员自已把握,随意性相当大;靠管理人员把握,主观性又太强。采用CVS管理后,开发人员每天下班前对修改的文件 Check In,其中记述当天修改细节描述,这些描述可以作为工作量的衡量指标。 

    (2) 规范测试 

    采用CVS以后,测试有了实实在在的工作,测试工作人员根据每天的修改细节描述对每一天的工作做具体的测试,对测试人员也具有可考核性,这样环环相扣,大大减少了其工作的随意性。 

    (3) 加强协调与沟通 

    采用CVS后,通过VSS文档共享系统和 Bugzilla缺陷跟踪系统,大大加强了项目成员之间的沟通,做到有问题及时发现、及时修改、及时通知,但又不额外增加很多的工作量。

     

  • 测试用例设计

    2007-06-15 15:14:58

    测试用例设计

      测试需求收集完毕后,开始测试设计。测试用例是什么?测试用例就是一个文档,描述输入、动作、或者时间和一个期望的结果,其目的是确定应用程序的某个特性是否正常的工作。设计测试用例需要考虑以下问题:

      测试用例的基本格式

      软件测试用例的基本要素包括测试用例编号、测试标题、重要级别、测试输入、操作步骤、预期结果,下面逐一介绍。

      用例编号: 测试用例的编号有一定的规则,比如系统测试用例的编号这样定义规则: PROJECT1-ST-001 ,命名规则是项目名称+测试阶段类型(系统测试阶段)+编号。定义测试用例编号,便于查找测试用例,便于测试用例的跟踪。

      测试标题: 对测试用例的描述,测试用例标题应该清楚表达测试用例的用途。比如测试用户登录时输入错误密码时,软件的响应情况

      重要级别: 定义测试用例的优先级别,可以笼统的分为两个级别。一般来说,如果软件需求的优先级为,那么针对该需求的测试用例优先级也为;反之亦然,

      测试输入: 提供测试执行中的各种输入条件。根据需求中的输入条件,确定测试用例的输入。测试用例的输入对软件需求当中的输入有很大的依赖性,如果软件需求中没有很好的定义需求的输入,那么测试用例设计中会遇到很大的障碍。

      操作步骤: 提供测试执行过程的步骤。对于复杂的测试用例,测试用例的输入需要分为几个步骤完成,这部分内容在操作步骤中详细列出。

      预期结果: 提供测试执行的预期结果,预期结果应该根据软件需求中的输出得出。如果在实际测试过程中,得到的实际测试结果与预期结果不符,那么测试不通过;反之则测试通过。

      软件测试用例的设计主要从上述 6 个域考虑,结合相应的软件需求文档,在掌握一定测试用例设计方法的基础上,可以设计出比较全面、合理的测试用例。具体的测试用例设计方法可以参见相关的测试书籍,白盒测试方法和黑盒测试方法在绝大多数的软件测试书籍中都有详细的介绍,这里不作赘述。

      重用同类型项目的测试用例

      如果我看得远,那是因为我站在巨人的肩上 --牛顿。

      一般来说,每个软件公司的项目可以分为固定的几大类。可以按业务类型划分,比如 ERP 软件、产品数据管理软件、通信软件、地理信息系统软件等等;可以按软件结构来划分,比如 B/S 架构的软件、 C/S 架构的软件、嵌入式软件等等。参考同类别软件的测试用例,会有很大的借鉴意义。如果,公司中有同类别的软件系统,千万别忘记把相关的测试用例拿来参考。如果,系统非常接近,甚至经过对测试用例简单修改就可以应用到当前被测试的软件。拿来主义可以极大的开阔测试用例设计思路,也可以节省大量的测试用例设计时间。

      利用已有的软件 Checklist

      在上面一个小节中,按照不同的规则划分了不同的软件类型。每种类型的软件都有一定的测试规范,比如, WEB 软件系统在系统测试过程中,会有一系列的范式,比如针对 Cookie 就会有很多测试点。在设计测试用例的时候,不妨到网上去搜索相关的 Checklist ,不过国内外的网站很少有这方面的资料,即便有,也不是特别系统。可以先找一份粗糙的 Checklist ,然后,在设计测试用例的时候不断的去完善它,以作为下次测试用例设计的基础。

      加强测试用例的评审

      测试用例设计完毕后,最好能够增加评审过程。同行评审是 CMM3 级的一个 KPA ,如果因为公司没有通过 CMM3 级,就不开展同行评审是不恰当的。测试用例应该由产品相关的软件测试人员和软件开发人员评审,提交评审意见,然后根据评审意见更新测试用例。 如果认真操作这个环节,测试用例中的很多问题都会暴露出来,比如用例设计错误、用例设计遗漏、用例设计冗余、用例设计不充分等等;如果同行评审不充分,那么,在测试执行的过程中,上述本应在评审阶段发现的测试用例相关问题,会给测试执行带来大麻烦,甚至导致测试执行挂起。

      定义测试用例的执行顺序

       

        在测试用例执行过程中,你会发现每个测试用例都对测试环境有特殊的要求,或者对测试环境有特殊的影响。因此,定义测试用例的执行顺序,对测试的执行效率影响非常大。比如某些异常测试用例会导致服务器频繁重新启动,服务器的每次重新启动都会消耗大量的时间,导致这部分测试用例执行也消耗很多的时间。那么在编排测试用例执行顺序的时候,应该考虑把这部分测试用例放在最后执行,如果在测试进度很紧张的情况下,如果优先执行这部分消耗时间的异常测试用例,那么在测试执行时间过了大半的时候,测试用例执行的进度依然是缓慢的,这会影响到测试人员的心情,进而导致匆忙地测试后面的测试用例,这样测试用例的漏测、误测就不可避免,严重影响了软件测试效果和进度。因而,合理地定义测试用例的执行顺序是很有必要的。

      测试用例执行

      测试用例设计完毕后,接下来的工作是测试执行,测试执行中应该注意以下几个问题:

      搭建软件测试环境,执行测试用例

      测试用例执行过程中,搭建测试环境是第一步。一般来说,软件产品提交测试后,开发人员应该提交一份产品安装指导书,在指导书中详细指明软件产品运行的软硬件环境,比如要求操作系统系统是 Windows 2000 pack4 版本,数据库是 Sql Server 2000 等等,此外,应该给出被测试软件产品的详细安装指导书,包括安装的操作步骤、相关配置文件的配置方法等等。对于复杂的软件产品,尤其是软件项目,如果没有安装指导书作为参考,在搭建测试环境过程中会遇到种种问题。

      如果开发人员拒绝提供相关的安装指导书,搭建测试中遇到问题的时候,测试人员可以要求开发人员协助,这时候,一定要把开发人员解决问题的方法记录下来,避免同样的问题再次请教开发人员,这样会招致开发人员的反感,也降低了开发人员对测试人员的认可程度。

      测试执行过程应注意的问题

      测试环境搭建之后,根据定义的测试用例执行顺序,逐个执行测试用例。在测试执行中需要注意以下几个问题:

      全方位的观察测试用例执行结果: 测试执行过程中,当测试的实际输出结果与测试用例中的预期输出结果一致的时候,是否可以认为测试用例执行成功了?答案是否定的即便实际测试结果与测试的预期结果一致,也要查看软件产品的操作日志、系统运行日志和系统资源使用情况,来判断测试用例是否执行成功了。全方位观察软件产品的输出可以发现很多隐蔽的问题。以前,我在测试嵌入式系统软件的时候,执行某测试用例后,测试用例的实际输出与预期输出完全一致,不过在查询 CPU 占用率地时候,发现 CPU 占用率高达 90 %,后来经过分析,软件运行的时候启动了若干个 1ms 的定时器,大量的消耗的 CPU 资源,后来通过把定时器调整到 10ms CPU 的占用率降为 7 %。如果观察点单一,这个严重消耗资源的问题就无从发现了。

      加强测试过程记录: 测试执行过程中,一定要加强测试过程记录。如果测试执行步骤与测试用例中描述的有差异,一定要记录下来,作为日后更新测试用例的依据;如果软件产品提供了日志功能,比如有软件运行日志、用户操作日志,一定在每个测试用例执行后记录相关的日志文件,作为测试过程记录,一旦日后发现问题,开发人员可以通过这些测试记录方便的定位问题。而不用测试人员重新搭建测试环境,为开发人员重现问题。

      及时确认发现的问题: 测试执行过程中,如果确认发现了软件的缺陷,那么可以毫不犹豫的提交问题报告单。如果发现了可疑问题,又无法定位是否为软件缺陷,那么一定要保留现场,然后知会相关开发人员到现场定位问题。如果开发人员在短时间内可以确认是否为软件缺陷,测试人员给予配合;如果开发人员定位问题需要花费很长的时间,测试人员千万不要因此耽误自己宝贵的测试执行时间,可以让开发人员记录重新问题的测试环境配置,然后,回到自己的开发环境上重现问题,继续定位问题。

      与开发人员良好的沟通: 测试执行过程中,当你提交了问题报告单,可能被开发人员无情驳回,拒绝修改。这时候,只能对开发人员晓之以理,做到有理、有据,有说服力。首先,要定义软件缺陷的标准原则,这个原则应该是开发人员和测试人员都认可的,如果没有共同认可的原则,那么开发人员与测试人员对问题的争执就不可避免了。此外,测试人员打算说服开发人员之前,考虑是否能够先说服自己,在保证可以说服自己的前提下,再开始与开发人员交流。

      及时更新测试用例

      测试执行过程中,应该注意及时更新测试用例。往往在测试执行过程中,才发现遗漏了一些测试用例,这时候应该及时的补充;往往也会发现有些测试用例在具体的执行过程中根本无法操作,这时候应该删除这部分用例;也会发现若干个冗余的测试用例完全可以由某一个测试用例替代,那么删除冗余的测试用例。

      总之,测试执行的过程中及时地更新测试用例是很好的习惯。不要打算在测试执行结束后,统一更新测试用例,如果这样,往往会遗漏很多本应该更新的测试用例。

      提交一份优秀的问题报告单

      软件测试提交的问题报告单和测试日报一样,都是软件测试人员的工作输出,是测试人员绩效的集中体现。因此,提交一份优秀的问题报告单是很重要的。软件测试报告单最关键的域就是问题描述,这是开发人员重现问题,定位问题的依据。问题描述应该包括以下几部分内容:软件配置、硬件配置、测试用例输入、操作步骤、输出、当时输出设备的相关输出信息和相关的日志等。

      软件配置: 包括操作系统类型版本和补丁版本、当前被测试软件的版本和补丁版本、相关支撑软件,比如数据库软件的版本和补丁版本等。

      硬件配置: 计算机的配置情况,主要包括 CPU 、内存和硬盘的相关参数,其它硬件参数根据测试用例的实际情况添加。如果测试中使用网络,那么网络的组网情况,网络的容量、流量等情况。硬件配置情况与被测试产品类型密切相关,需要根据当时的情况,准确翔实的记录硬件配置情况。

      测试用例输入 \ 操作步骤 \ 输出: 这部分内容可以根据测试用例的描述和测试用例的实际执行情况如实填写。

      输出设备的相关输出信息: 输出设备包括计算机显示器、打印机、磁带等等输出设备,如果是显示器可以采用抓屏的方式获取当时的截图,其他的输出设备可以采用其它方法获取相关的输出,在问题报告单中提供描述。

      日志信息: 规范的软件产品都会提供软件的运行日志和用户、管理员的操作日志,测试人员应该把测试用例执行后的软件产品运行日志和操作日志作为附件,提交到问题报告单中。

      根据被测试软件产品的不同,需要在问题描述中增加相应的描述内容,这需要具体问题具体分析。

      测试结果分析

      软件测试执行结束后,测试活动还没有结束。测试结果分析是必不可少的重要环节,编筐编篓,全在收口,测试结果的分析对下一轮测试工作的开展有很大的借鉴意义。前面的测试准备工作中,建议测试人员走读缺陷跟踪库,查阅其他测试人员发现的软件缺陷。测试结束后,也应该分析自己发现的软件缺陷,对发现的缺陷分类,你会发现自己提交的问题只有固定的几个类别;然后,再把一起完成测试执行工作的其他测试人员发现的问题也汇总起来,你会发现,你所提交问题的类别与他们有差异。这很正常,人的思维是有局限性,在测试的过程中,每个测试人员都有自己思考问题的盲区和测试执行的盲区,有效的自我分析和分析其他测试人员,你会发现自己的盲区,有针对性的分析盲区,必定会在下一轮测试用避免盲区。

      总结:

      限于文章的篇幅,本文不可能给出一个类似于 checklist 的指导性的软件测试新手入门。无论从事软件测试还是从事其它的工作,技术上的和技巧上的问题都可以通过查询相关的软件测试技术书籍获取,掌握一套基本的方法论是最重要的。以上文字,都是作者从事软件测试工作积累的经验之谈,如发现谬误之处请不吝指出。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 冒烟测试是什么?

    2007-06-15 14:35:19

    关于冒烟测试,应该是微软首先提出来的一个概念,和微软一直提倡的每日build有很密切的联系。具体说,冒烟测试就是在每日build建立后,对系统的基本功能进行简单的测试。这种测试强调功能的覆盖率,而不对功能的正确性进行验证。

    就象生产汽车一样,汽车生产出来以后,首先发动汽车,看汽车能否冒烟,如果能,证明汽车最起码可以开动了。说明完成了最基本的功能。

      冒烟测试一般用于每日构建(Nightly build),构建服务器首先从CVS服务器上,下载最新的源代码,然后编译单元测试,运行单元测试通过后,编译可执行文件,可执行文件若可运行,并能执行最基本的功能,则认为通过了冒烟测试,这时,构建服务器会把程序打包成安装文件,然后上传到内部网站,第二天一早,测试人员来了以后,会收到构建服务器发来的邮件提示昨晚是否构建成功。若构建成功,则测试人员进行相关的功能测试。所有这些功能的完成,一般是靠编写脚本完成的,目前比较常用的脚本有TCL,Perl,Python及功能弱弱的批处理。用这些可以完成系统的每日构建。

      简单的说,就是先保证系统能跑的起来,不至于让测试工作做到一半突然出现错误导致业务中断。目的就是先通过最基本的测试,如果最基本的测试都有问题,就直接打回开发部了,减少测试部门时间的浪费。

  • 软件项目测试管理经验谈

    2007-06-15 10:14:58

    一、软件测试员自身素质培养

        1 首先,应对软件测试感兴趣和对自己有自信,如果具备了这两点,那么在开发过程中不管遇到什么样的困难,我相信你一定能克服。

        2 善于怀疑,世界上没有绝对正确的,总有错误的地方,具有叛逆心理,别人认为不可能发生的事,我却认为可能发生。别人认为是对的,我却认为不是对的。

        3 打破砂锅问到底的精神,对于只出现过一次的bug,一定找出原因,不解决誓不罢休。

        4 保持一个良好的心情,否则可能无法把测试作好。不要把生活中的不愉快的情绪带到工作中来。

        5 做测试时要细心,不是所有的bug都能很容易的找出,一定要细心才能找出这些bug

        6 灵活一些,聪明一点,多制造一些容易产生bug的例子。

        7 在有条件的情况下,多和客户沟通,他们身上有你所需要的。

        8 设身处地为客户着想,从他们的角度去测试系统。

        9 不要让程序员,以这种情况不可能发生这句话说服你,相反,你应该去说服他,告诉他在客户心里,并不是这样的。

        10 考虑问题要全面,结合客户的需求、业务的流程、和系统的构架,等多方面考虑问题。

        11 提出问题不要复杂化,这一点和前面的有点矛盾,如果你是一新手,暂时不要管这一点,因为最终将有你的小组成员讨论解决。

        12 追求完美,对于新测试员来说,努力的追求完美,这对你很好,尽管有些事无法做到,但你应该去尝试。

        13 幽默感,能和开发小组很好的沟通是关键,试着给你的开发小组找一个“BUG杀手,或对他们说我简直不敢相信,你写的程序居然到现在没有找到BUG”

        14 到此是不是对测试很有兴趣呢?不过我要告诉你,测试过程中有酸甜苦辣,其中的滋味只有你知道,也许你会感到枯燥,要学会放松自己,去溜冰或做你喜欢做的事,不过,别放弃,因为你的自信告诉过你你会是很优秀的测试员不是吗?

        二、浅谈软件测试之技巧

        
    软件测试虽然辛苦,但是掌握了一定的技巧之后将使你事半功倍。

        1 边界测试,测试用户输入框中的数值的最大数和最小数,以及为空时的情况。

        2 非法测试,例如在输入数字的地方输入字母。

        3 跟踪测试,跟踪一条数据的流程,保证数据的正确性。

        4 在开始测试时应保证数据的正确性,然后在从系统中找出各种BUG

        5 接口测试,程序往往在接口的地方很容易发生错误,要在此模块测试勿掉以轻心。

        6 代码重用测试,在开发过程中有些模块功能几乎相同,程序员在重用代码时可能忘记在原有代码上修改或修改不全面,而造成的错误。

        7 突发事件测试,服务器上可能发生意外情况的测试。

        8 外界环境测试,有些系统在开发时依赖于另外一个系统,当另外一个系统发生错误时, 这个系统所受到的影响的情况。

        9 在程序员刚修复Bug之后的地方,再找一找,往往程序员只修复报告出来的缺陷而不去考虑别的功能在修改时可能会重新造成错误。

        10 认真做好测试记录在做完一天的测试记录之后,第二天再根据第一天的测试记录重复测试你会发现有未修正的错误。

        11 文字测试,如果在系统中有用词不当的地方,我想这是不应该的。

        12 系统兼容测试,例如有些程序在IE6能运行正常,到IE5下不能运行。有些程序在WIN2000下能运行,而到WIN98却不能运行。像一些很特别的用户去使用系统,你很有可能发现BUG

        13 用户的易用性测试,往往用户的需求是不断的变化的,而其中的一部份变化的原因,是有用户操作上不方便引起的。

        软件测试是软件开发中的重中之重,没有一点可以马虎的,在项目管理过程,强调的是每个过程的每一个环节都要进行测试,保证系统在每个阶段可以控制。因为软件测试中考虑的问题基本上是项目管理中考虑的问题。 工作中真的需要多总结,多剖析,对于毛病:有则改之、无则加冕

        软件开发是一件很辛苦的事,只有在工作中多总结,才能找到符合自己的方式方法,才能在工作中事半功倍。

     

     

853/5<12345>
Open Toolbar