SQA,测试管理,软件测试,测试流程

发布新日志

  • 转:性能测试的方法

    2007-09-19 17:42:18

  • 转:使用IBM Rational的测试理念成功打造测试团队

    2007-09-19 17:39:03

    文本讲述了 IBM Rational 在软件测试方面的理念以及 Ratioanl 的测试产品方案,你可以了解到如何 使用 IBM Rational 的测试理念成功打造测试团队 。
    1. 传统软件测试过程中的问题

    测试在所有的软件开发过程中都是最重要的部分。在软件开发过程中,一方面要求我们通过测试活动验证所开发的软件在功能上满足软件需求中描述的每一条特性,性能上满足客户要求的负载压力和相应的响应时间、吞吐量要求;另一方面,面向市场和客户,开发团队还要满足在预算范围内尽快发布软件的要求。

    传统的软件测试流程一般是先在软件开发过程中进行少量的单元测试,然后在整个软件开发结束阶段,集中进行大量的测试,包括功能和性能的集成测试和系统测试。随着开发的软件项目越来越复杂,传统的软件测试流程不可避免地给我们的工作带来以下问题:

    问题一:项目进度难于控制,项目管理难度加大
    如图一所示,大量的软件错误往往只有到了项目后期系统测试时才能够被发现,解决问题所花的时间很难预料,经常导致项目进度无法控制,同时在整个软件开发过程中,项目管理人员缺乏对软件质量状况的了解和控制,加大了项目管理难度。

    figure1
    图一、传统测试流程中存在的问题

    问题二:对于项目风险的控制能力较弱
    项目风险在项目开发较晚的时候才能够真正降低。往往是经过系统测试之后,才真正确定该设计是否能够满足系统功能、性能和可靠性方面的需求。

    问题三:软件项目开发费用超出预算

    在整个软件开发周期中,错误发现的越晚,单位错误修复成本越高,如图二所示,错误的延迟解决必然导致整个项目成本的急剧增加。

    figure2

    图二、传统测试流程中存在的问题


    2. 采用IBM Rational软件自动化测试最佳成功经验解决传统测试问题

    IBM Rational软件自动化测试技术核心的三个最佳成功经验是:尽早测试、连续测试、自动化测试,并在此基础上提供了完整的软件测试流程和一整套的软件自动化测试工具,使我们最终能够做到:一个测试团队,基于一套完整的软件测试流程,使用一套完整的自动化软件测试工具,完成全方位的软件质量验证。

    2.1 成功经验一:尽早测试

    所谓尽早测试是指在整个软件开发生命周期中通过各种软件工程技术尽量早的完成各种软件测试任务的一种思想。IBM Rational主要在以下三个方面为我们提供的尽早测试的软件工程技术:

    首先,软件的整个测试生命周期是与软件的开发生命周期基本平齐的过程,如图三所示,即当需求分析基本明确后我们就应该基于需求分析的结果和整个项目计划来进行软件的测试计划;伴随着分析设计过程同时应该完成测试用例的设计;当软件的第一个发布出来后,测试人员要马上基于它进行测试脚本的实现,并基于测试计划中的测试目的执行测试用例,对测试结果进行评估报告。这样,我们可以通过各种测试指标实时监控项目质量状况,提高对整个项目的控制和管理能力。

    figure3

    图三、软件测试生命周期

    其次,通过迭代是软件开发把原来的整个软件开发生命周期分成多个迭代周期,在每个迭代周期都进行测试,这样在很大程度上提前了软件系统测试发生的时间,这可以在很大程度上降低项目风险和项目开发成本。

    最后,IBM Rational的尽早测试成功经验还体现在它扩展了传统软件测试阶段从单元测试、集成测试到系统测试、验收测试的划分,将整个软件的测试按阶段划分成开发员测试和系统测试两个阶段,如图四所示,它把软件的测试责无旁贷地扩展到整个开发人员的工作过程。通过提前测试发生的时间来尽早地提高软件质量、降低软件测试成本。

    figure4

    图四、IBM Rational测试方法对测试阶段的划分

    2.2 成功经验二:连续测试

    测试成功经验连续测试是从迭代式软件开发模式得来。在迭代化的方法中,我们将整个项目的开发目标划分成为一些更易于完成和达到的阶段性小目标,这些小目标都有一个定义明确的阶段性评估标准。迭代就是为了完成一定的阶段性目标而从事的一系列开发活动,在每个迭代开始前都要根据项目当前的状态和所要达到的阶段性目标制定迭代计划,而且每个迭代中都包括需求、设计、编码、集成、测试等一系列的开发活动,都会增量式集成一些新的系统功能。通过每次迭代,我们都产生一个可运行的系统,通过对于这个可运行系统的测试来评估该次迭代有没有达到预定的迭代目标,并以此为依据来制定下一次迭代的目标。由此可见,在迭代式软件开发的每个迭代周期我们都会进行软件测试活动,整个软件测试的完成是通过每个迭代周期不断增量测试和回归测试实现的。

    如图五所示,采用连续测试的软件成功测试经验,不但能够持续的提高软件质量、监控质量状态,同时也使系统测试的尽早实现成为可能。从而有效的控制开发风险、减低测试成本和保证项目进度。

    figure5

    图五、IBM Rational测试成功经验:连续测试

    2.3 成功经验三:自动化测试

    在整个软件的测试过程中要想实现尽早测试、连续测试,可以说完善的测试流程是前提,自动化测试工具是保证。IBM Rational的自动化测试成功经验主要是指利用软件测试工具提供完整的软件测试流程的支持和各种测试的自动化实现。

    为了使各种软件测试团队更好地进行测试,IBM Rational在提供了测试成功经验之外,还为我们提供了一整套的软件测试流程和自动化测试工具,使软件测试团队能够从容不迫地完成整个测试任务。

    3. IBM Rational软件自动化测试工具

    在IBM Rational的软件自动化测试解决方案中,我们一直致力追求的一点就是测试工具和测试成功经验、测试流程的统一,上面阐述的每个测试成功经验和测试流程环节,我们都可以通过Rational的测试工具以及工具间的完美集成辅助完成。

    IBM Rational的软件自动化测试工具如图七所示,其最大特点是通过一套完整的软件测试工具在实现测试管理流程的基础上,同时涵盖了功能测试、性能测试和可靠性测试的自动化测试需求,通过工具之间的集成完成测试资源的整合,帮助测试团队实现IBM Rational的测试成功经验。

    figure6

    图七、IBM Rational自动化测试工具


    4. IBM Rational软件测试流程

    IBM Rational的软件测试流程,不仅仅包含完整的软件测试流程框架,同时还提供了内嵌软件测试流程的测试管理工具的支持。

    4.1 IBM Rational软件测试流程框架

    IBM Rational Unified Process(以下简称RUP)提供了一套完整的测试流程框架,软件测试团队可以以它为基础,根据业务发展的实际要求,定制符合团队使用的软件测试流程。RUP中的软件测试流程如图六所示:

    figure7

    图六、IBM Rational 软件测试流程

    每个测试环节的具体阐述如下:

    制定测试计划的目的是确定和描述要实施和执行的测试。这是通过生成包含测试需求和测试策略的测试计划来完成的。可以制定一个单独的测试计划,用于描述所有要实施和执行的不同测试类型,也可以为每种测试类型制定一个测试计划。
    设计测试的目的是确定、描述和生成测试过程和测试用例。
    实施测试的目的是实施(记录、生成或编写)设计测试中定义的测试过程。输出工件是测试过程的计算机可读版本,称为测试脚本。
    执行测试的目的是确保整个系统按既定意图运行。系统集成员在各迭代中编译并链接系统。每一迭代都需要测试增加的功能,并重复执行以前版本测试过的所有测试用例(回归测试)。
    评估测试的目的是生成并交付测试评估摘要。这是通过复审并评估测试结果、确定并记录变更请求,以及计算主要测试评测方法来完成的。测试评估摘要以组织有序的格式提供测试结果和主要测试评测方法,用于评估测试对象和测试流程的质量。

    4.2 利用IBM Rational软件测试管理平台实现软件自动化测试流程

    IBM Rational在RUP测试方法论的基础上构建了软件自动化测试管理平台工具TestManager,通过和测试需求管理工具RequisitePro、缺陷追踪工具ClearQuest的完美集成,实现了对整个软件测试生命周期的管理,可以帮助软件测试团队快速建立软件测试平台和测试管理流程,使软件测试团队快速拥有以下能力:

    TestManager提供测试管理的核心平台,整合了从测试需求、测试计划、测试设计、测试实施、测试执行到测试结果分析、测试报告的自动生成等整个测试生命周期的管理活动。同时,统一组织各种Test Suite,Test Case,Test scrīpt,方便地进行回归测试
    TestManager遵循RUP标准测试流程,使测试人员能够在统一的测试管理平台上、遵循统一的测试管理流程,完成对包括产品的功能性、可靠性和性能等全方位的质量测试。
    作为一种集成解决方案,Rational TestManager与Rational 其他工具一起,提供从测试需求、到整个软件测试流程管理、缺陷追踪、测试结果评测的可追踪性,方便测试管理人员进行软件测试过程监控和有关软件质量的各种量化指标的采集、分析。

    4.3 利用IBM Rational软件测试工具实现软件自动化的功能和性能测试

    IBM Rational的自动化软件测试工具的另一个特点就是:通过TestManager + Robot,在实现测试管理流程的同时,能够完成功能测试和性能测试,这会大大缩短测试团队对工具的学习过程,提高工具的易用性。

    4.3.1 软件的自动化功能测试

    功能测试主要围绕Windows图形界面、字符终端和Browser界面进行测试。客户端可以是VC、VB、PB、Delphi等编制的软件、各种字符终端软件或者运行浏览器Microsoft Explorer和Netscape,通过自动录制形成测试脚本实现自动化的功能/回归测试。

    IBM Rational的功能测试解决方案的目标,是使功能性测试变得更简单、有效并可重复执行,从而快速提升软件测试团队的功能测试能力。它主要具有以下特点:

    能够方便的对各种环境(IDE)中开发的应用程序、字符终端软件,完成包括测试计划、测试设计、测试实施、测试执行和测试结果分析等全部测试流程。
    能够方便的录制或编写各种功能测试脚本,实现自动化的功能/回归测试。
    利用数据池方便地解决大批量数据驱动的功能测试;
    能够方便地完成分布式功能测试,可以一次测试多种测试平台;
    能够自动完成功能测试需求覆盖,确保应用程序满足产品规格说明和测试计划的每一条业务需求;
    为了提高对Java和Web开发的应用软件功能测试的支持,IBM Rational的功能测试的解决方案还提供了IBM Rational XDE Tester,它主要用于在Windows和Linux平台上基于Java和Web开发的应用软件的功能测试,尤其适用于使用IBM WebSphere Studio、Eclipse和 Rational XDE Developer等开发平台进行软件开发的团队。它的三个最重要的自动化测试的特性是:

    专业的自动化测试脚本创建环境:测试平台扩展嵌入到IBM WebSphere Studio、Eclipse和 Rational XDE Developer开发平台,统一了测试和开发环境;
    测试脚本在回归测试方面具有很强的灵活性和可维护性:scrīptAssure是 IBM提供的针对 Java 和Web应用程序测试时的一组高级能力, 它能够帮助创建灵活、可重用的测试脚本,大大提高了脚本的可维护性。对象地图(Object mapping)提供了核心对象库,测试人员可以基于它进行被测程序中被测对象的修改和验证,并根据修改自动更新所有相关的测试脚本。可以自己设置被测程序中用来表示被测对象的对象属性集,这使得少量对象属性的变化不会影响测试脚本的正常回放。同时,可以创建针对动态数据的验证点,通过正则表达式更容易对动态的数据进行验证;
    强大的测试脚本语言:使用标准的测试脚本语言Java,可以充分利用工业标准语言的优点进行测试。

    4.3.2 软件的自动化压力测试

    IBM Rational压力测试工具主要目标是快速提升软件测试团队的性能测试能力,包括负载测试,压力测试等等。Rational性能测试解决方案可以方便灵活地模拟各种负载模型,完成以查找响应时间瓶颈、系统吞吐量、最大并发虚拟用户等为目地的各种要求的性能测试。包括:

    利用TestStudio可以完成对压力测试的测试需求、测试计划、测试设计、测试实施、测试执行和测试结果分析等整个测试生命周期的管理;
    利用TestStudio中的Test Suite,能够方便的完成压力测试对负载模型的各种要求,包括:

    建立复杂的Scenario模型;
    准确模拟复杂负载的时序控制;
    基于Transaction的负载分析;
    建立面向目标的事务负载模型,例如:100事务/秒
    响应时间精确到1/100秒;
    支持不同虚拟用户的不同IP地址模拟;
    准确的波特率模拟;
    利用TestStudio,能够方便地完成压力测试过程中各种指标的观测;
    利用TestStudio,能够方便地完成压力测试结果分析和各种结果报告的生成;
    4.4 利用IBM Rational软件测试工具实现软件自动化的可靠性测试和单元测试

    IBM Rational软件测试工具PurifyPlus主要用于帮助软件测试团队在短期内快速提升单元测试能力和可靠性测试能力的团队,其主要特点是:见效快、使用方便、门槛低、培训时间短,开发人员2小时内即可完全掌握该软件进行测试。PurifyPlus包含Rational Purify、Quantify和PureCoverage三个产品,主要功能如下:

    Rational Purify主要针对软件开发过程中难于发现的内存错误、运行时错误。在软件开发过程中:

    自动地发现错误;
    准确地定位错误;
    提供完备的错误信息;

    从而减少了调试时间, 帮助开发团队找出缺陷并最终形成高质量的产品,使您能真正做到更快地发布更好的软件。
    Rational Quantify主要解决软件开发过程中的性能问题。在软件开发过程中:

    方便地查明并显示应用程序的性能瓶颈,从而确保整个应用程序的质量和性能。
    Rational Quantify 给开发团队提供了一个性能数据的全局图形化视图,使您从开发流程的开头起就注重性能问题,真正做到更快地发布更好的软件。
    Rational PureCoverage提供应用程序的测试覆盖率信息。在软件开发过程中:

    能自动找出代码中未经测试的代码,保证代码测试覆盖率;
    帮助开发人员确保开发质量,并使质量保证人员能够评价测试工作的效果。
    可针对每次测试生成全面的覆盖率报告,可以归并程序多次运行所生成的覆盖数据,并自动比较测试结果,以评估测试进度。

    4.5 利用IBM Rational软件测试工具实现实时系统软件的自动化测试

    IBM Rational Test Realtime主要适合于开发实时系统和具有较高要求的非实时系统的软件开发,可以帮助测试团队快速建立起单元测试、集成测试、系统测试等测试能力。它提供的自动测试(包括单元测试、集成测试、系统测试)、代码覆盖、内存泄漏检查、性能分析以及UML跟踪等重要特性,帮助软件测试团队在系统崩溃前发现并修复软件缺陷。其主要功能特性如下:

    自动生成测试脚本模板和测试程序(包括驱动模块和桩模块):通过源代码分析,自动生成在目标上运行所需的测试脚本和测试程序。除了利用测试脚本指定测试数据外,不需要手工编码。而且在测试报告中,测试结果和源代码相联,简化代码修改;
    通过代码自动插针进行代码覆盖率、内存泄漏以及性能瓶颈进行分析,并和测试用例建立关联;
    通过把测试结果和观察结果和被测代码关联,把测试作为开发的一个重要部分,真正实现边开发边测试,边测试边观察,边观察边评估这一集成的开发测试过程;
    通用的、低开销而且易于移植的目标适配技术(Target Deployment Port,TDP):利用TDP技术,使得测试与编译器、连接器、调试器以及目标结构无关,实现了跨多开发环境、多目标结构;
    模型观察和代码覆盖相集成:利用UML Trace功能观察应用运行状态,并通过状态机模型覆盖实现测试用例和模型的关联,充分利用了模型和代码级测试的长处;
    与ClearCase、ClearQuest和RUP集成:在同一集成环境中完成对测试文件进行版本控制,提交和修改变更请求;

    5. 小结

    图八、IBM Rational的软件自动化测试解决方案

    IBM Rational主要为软件测试团队提供测试成功经验、自动化测试工具和全方位的咨询服务三方面的支持,如图八所示,最终实现:一个测试团队,基于一套完整的软件测试流程,使用一套完整的自动化软件测试工具,完成全方位的软件质量验证,这正是IBM Rational测试解决方案的精髓和终极目标

  • 转:国际化软件测试的特征分析

    2007-09-19 17:17:29

    经济的全球化促进了软件产业的国际化,软件国际化生产和全球服务成为更多国际软件公司的发展策略。软件产品要获得更多的国际市场份额,必须进行软件国际化设计、开发、测试和服务。

    按照国际化要求生产的软件称为国际化软件,从实现技术和生产过程分析,国际化软件包括软件国际化和软件本地化两个相辅相成的环节。软件国际化保证软件具有“全球可用”的内在特征,而软件本地化可以满足目标市场的用户在语言、文化和功能的需要。

    国际化软件测试具有测试多方参与、跨国家 / 地区范围广、测试内容广泛、测试周期时效性强等特点。国际化软件测试的两个显著特征是缺陷跟踪工具驱动测试和项目里程碑驱动测试。

    国际化软件开发流程

    I18n process

    对于国际化软件而言,完整地开发周期将包括需求分析、国际化、本地化、发布和维护等过程。其中国际化包括设计、开发和测试等,在国际化的各个环节都要重视软件的本地化能力。

    国际化软件的开发流程包括开发国际化软件需要遵循软件工程的要求,分为需求分析、软件设计、软件编码、软件测试、质量保证、软件发布等过程。国际化软件的开发流程如下图所示:

    在需求分析阶段,既要考虑软件的功能需求,也要考虑软件的国际化需求。另外,为了缩短源语言开发的版本和本地化版本的发布时间间隔(甚至达到同步发布),国际化版本的开发应该与软件本地化过程同时进行。在测试方面,对国际化版本的国际化功能测试和对本地化版本的本地化测试尽可能同时进行,以便尽早发现和修改国际化设计错误。

    缺陷跟踪工具驱动的测试

    I18n tool

    国际化软件规模大、用户范围广、对质量的要求严格,所以软件测试过程中将发现和报告大量的软件缺陷。这些不同类型的软件缺陷分别由不同角色的项目成员负责处理,由于测试人员和开发人员可能分布在不同的国家和地区,因此,需要使用满足软件缺陷全球管理的软件缺陷跟踪( Defect Tracking System - DTS )系统。

    为了达到全球通用的目的,基于因特网的缺陷跟踪系统成为必选条件。借助全球的软件缺陷系统,软件项目团队的全体成员以软件缺陷跟踪系统为工作的参照物,如上图所示。测试人员向缺陷跟踪系统报告新 Bug ,在新版本上执行回归测试验证 Bug 是否正确修正;开发人员每天浏览属于自己需要处理的 Bug ,修正 Bug 后及时更新 Bug 的状态;项目经理根据缺陷跟踪系统的 Bug 分布信息,跟踪和控制软件开发过程;市场销售和技术支持人员根据缺陷跟踪系统的 Bug 状况,估计软件的发布期限。

    里程碑驱动的软件测试
    I18n milestones

    里程碑( Milestone )是项目实施过程的各个关键阶段,在国际化软件开发和测试项目中,里程碑表示软件开发和测试的标志性、阶段性临界点。软件开发过程有多个计划的里程碑,分别表示软件到各个阶段所具有的功能和完成的任务。

    从软件周期来讲,软件主要里程碑包括基本功能完成编码,软件完成 Alpha Build 和 Beta Build ,完成预发布 Build ( RC Build ),完成 RTM Build 。软件项目的里程碑示意图如右图所示。这些不同阶段的里程碑的测试内容不同,测试方法不同,每一个里程碑对应一个关键的软件项目阶段,时效性非常强,为了做到软件项目按照项目计划按时发布,要求软件测试人员做好准备,在软件测试计划和项目进度计划安排的时间,完成相应地测试任务。

    在软件编码完成后的里程碑应该完成基本功能测试(单元测试、集成测试),基本完成国际化测试,当软件完成本地化;在 Alpha 和 Beta 测试阶段开始本地化测试,结束国际化测试; RC Build 阶段完成本地化测试, RTM Build 阶段完成验收测试

  • 转:单元测试的完整介绍

    2007-09-19 17:11:30

    这是一篇全面介绍单元测试的经典之作,对理解单元测试和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很有帮助,作者老纳,收录时作了少量修改]

  • 整理个人收集的测试资料

    2007-05-23 09:25:50

    • 常去的测试网站和论坛:
    • http://www.51cmm.com/
      http://www.testage.net/haisongbao/index.htm
      www.opentest.net
      http://www.testage.net/

      英文:
      www.stickyminds.com
      www.sqatester.com
      http://www.testassured.com/
      http://www.rspa.com/
      http://www.softtest.org/
    • 测试时代 http://www.testage.net/link.asp
      软件工程专家网:http://www.51cmm.com
      测试管理中心论坛:http://61.140.216.176:8010/ubbcgi/ultimatebb.cgi
      海松宝的小屋:http://yuanhaisong.myrice.com
      测试工程师:http://www.opentest.net
      软件测试杂货店:http://www.websamba.com/softtest
      飞龙工作室:http://freedragon.net
      UML软件工程组织:http://www.uml.net.cn
      配置管理论坛-SCM China:http://www.heynew.com/scmforum/default.asp
      软件配置管理:http://www.8848software.com
      UMLChina:http://www.umlchina.co
      http://21newtimes.yeah.net/ 新软件工程联盟
      http://www.codeclub.net/bbs/ 中华程序网
      http://expert.csdn.net/expert/forum.asp CSDN
      http://www.uml.net.cn/Test/test.htm 软件工程组织
      http://www.sercenter.com/KP/test.htm 软件工程研究中心
    • http://61.171.85.210/cgi-bin/forums.cgi?forum=25

     

数据统计

  • 访问量: 412021
  • 日志数: 8
  • 文件数: 1
  • 建立时间: 2007-05-18
  • 更新时间: 2007-09-19

RSS订阅

Open Toolbar