软件工程第7章软件测试.ppt
第7章 软件测试,内容提要,7.1 软件测试概述7.2 软件测试用例的设计7.3 软件测试的实施7.4 软件测试的面向对象方法简述7.5 本章小结,软件测试,软件系统的开发体现了人们智力劳动的成果。在软件开发过程中,由于人的主观认知能力的局限性和所开发软件的复杂性,尽管人们利用了许多旨在改进、保证软件质量的方法去分析、设计和实现软件,在软件生命周期的每个阶段还是不可避免地会产生错误。因此,在软件正式投入运行之前,必须通过严格的测试,来发现并纠正软件中的错误,从而保证软件的质量。大量的实践证明,测试是一项很艰苦的工作,据统计,软件测试的工作量往往占软件开发总工作量的40%以上。目前,程序的正确性证明在技术上尚未得到根本的解决,软件测试仍然是发现软件中错误和缺陷的主要手段。因此,必须高度重视软件测试工作。,软件测试,软件测试是软件质量保证的关键步骤,它包括分析、设计和编码的最终检查。软件测试的结果也是分析软件可靠性的重要依据。本章着重讨论软件测试的概念、传统软件和面向对象软件的测试问题。,7.1 软件测试概述,软件测试概述,7.1.1 软件测试的目标及原则 测试是对软件分析、设计、编码进行查错和纠错的活动。正确理解软件测试的概念和目标,对保证软件测试的成功实施起着极其重要的作用。从表面上来看,软件测试是具有“破坏”性质的,因为在测试阶段,测试人员努力设计出一系列测试方案,竭力发现和证明程序中错误的存在。而软件工程的其他阶段都是“建设性”的,软件工程师力图从抽象的概念出发,逐步设计出软件蓝图,再经过编码而实现软件产品。当然,这种反常仅仅是表面的或是心理上的,暴露问题并不是软件测试的最终目的,发现问题是为了改进软件设计或纠正程序的错误。测试阶段的根本目标是尽可能多地发现并排除软件中潜在的错误,最终把一个高质量的软件系统交给用户使用。,软件测试概述,以下三点可以看作是测试的目标:1.测试是为了发现程序中的错误而执行程序的过程。2.好的测试方案是尽可能发现至今为止尚未被发现的错误的测试方案。3.成功的测试是发现了至今为止尚未被发现的错误的测试。由此可以看出,测试的正确含义是“为了发现程序中的错误而执行程序的过程”。这和某些人想像的“测试是为了证明程序是正确的”,“成功的测试是没有发现错误的测试”等是完全相反的。明确测试的目的是一件非常重要的事情,因为在实际工作中对测试工作存在着许多模糊或错误的看法,这些看法严重影响着测试工作的顺利进行。测试的目标决定了测试方案的设计,如果为了表明程序是正确的,就会设计一些不易暴露错误的测试方案。相反,如果测试是为了发现程序中的错误,就会力求设计出最容易暴露错误的测试方案。,软件测试概述,基于以上的叙述,在设计软件测试方案前,软件开发者必须理解软件测试的基本原则。这些测试原则是:(1)坚持“尽早地和不断地进行软件测试”的原则。不应把软件测试仅仅看作是软件开发的一个独立阶段,而应当把它贯穿到软件开发的各个阶段中。坚持软件开发的各个阶段的技术评审,这样才能在开发过程中尽早发现和预防错误,把出现的错误克服在早期,杜绝某些错误发生的隐患。,软件测试概述,(2)测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成。测试以前应当根据测试的要求选择测试用例,用来检验程序员编制的程序,因此不但需要测试的输入数据,而且需要针对这些输入数据的预期输出结果。(3)程序员应避免测试自己的程序。由于思维定势和心理因素的影响,程序员并不是测试的最佳人选。这不能与程序的调试相混淆,调试由程序员自己来做可能更有效。而程序员以及程序开发小组应尽可能避免测试自己编写的程序。为了达到最佳效果,最好建立独立的软件测试小组或测试机构。(4)在设计测试用例时,应当包括合理的输入条件和不合理的输入条件。,软件测试概述,(5)充分注意测试中的群集现象。软件测试的实践表明:测试后模块中残存的错误数目与该模块的错误检出率成正比,即错误群集。根据这个规律,应当对发现错误较多的模块进行重点测试,以提高测试效率。(6)严格执行测试计划,排除测试的随意性。(7)应当对每个测试结果做全面检查。有些错误的征兆在输出测试结果时已经明显地出现了,但是如果不仔细地、全面地检查测试结果,就会使这些错误被遗漏掉。所以必须对预期的输出结果明确定义,对测试的结果仔细分析检查,暴露错误。(8)妥善保存测试计划、测试用例、出错统计和最终分析报告,为维护提供方便。,软件测试概述,7.1.2 软件错误产生的原因及分类 软件开发是一项极其复杂的智力活动,由于主观认知能力的局限性和所解决问题的复杂性,在表达、理解、验证用户需求,软件设计以及程序编写的过程中,都不可避免地会出现各式各样的错误,这些错误贯穿在软件生命周期的各个阶段。由于人们对错误有不同的理解和认识,基于不同的角度,有着不同的错误分类方法,所以目前还没有一个统一的错误分类方法。下面分别从错误的影响和后果、错误的性质和范围、错误产生的阶段作简单介绍。,软件测试概述,1.按错误的影响和后果分类(1)较小错误:只对系统的输出有一些非实质性影响。例如,输出的数据格式不符合要求等。(2)中等错误:对系统的运行有局部影响。如输出的某些数据有错误或出现冗余。(3)较严重错误:系统的行为因错误的干扰而出现异常现象。例如,错误的输入数据。(4)严重错误:系统运行不可跟踪,一时不能掌握其规律,时好时坏。(5)非常严重的错误:系统运行中突然停机,其原因不明,无法软启动。(6)最严重的错误:系统运行导致运行环境破坏,或是造成事故,引起生命、财产的损失。,软件测试概述,2.按错误的性质和范围分类(1)功能性错误 规格说明错误:规格说明可能不完全,有二义性或自相矛盾。功能错误:程序实现的功能与用户的要求不一致。测试错误:软件测试的设计与实施发生错误,软件测试自身也可能发生错误。测试标准引起的错误:若测试标准太复杂,则导致测试过程出错的可能性就大。,软件测试概述,(2)系统错误 硬件接口错误:软件运行相关的外部设备错误,导致系统运行故障。软件接口错误:数据输入.输出格式错误,软件通信协议错误等。操作系统错误:非法使用访问操作系统指令,访问指令错误。硬件结构错误:非法访问硬件指令。软件结构错误:软件体系结构设计不合理,导致负载较高时,系统运行不正常。控制与顺序错误:不合理的控制流程,导致某路径永远不能执行。资源管理错误:多任务环境中,由于资源共享,资源管理不当,导致系统死锁。,软件测试概述,(3)加工错误 算术与操作错误。初始化错误。控制和次序错误。静态逻辑错误。,软件测试概述,(4)数据错误 动态数据错误。静态数据错误。数据内容错误。数据结构错误。数据属性错误。,软件测试概述,(5)代码错误 主要包括语法错误、打字错误、对语句或指令的不正确理解所产生的错误。,软件测试概述,3.按软件生命周期阶段分类(1)需求分析错误 这类错误主要是指在理解和表达需求时产生的错误。不一致性错误:规格说明中功能说明与需求发生矛盾。冗余性错误:规格说明中的某些功能是多余的。不完整性错误:规格说明中缺少某些必要的功能说明。不可行错误:规格说明中有些功能要求是不可行的。不可测试错误:有些功能的测试要求是不现实的。,软件测试概述,(2)设计错误 这类错误主要是指在设计阶段产生的与需求规格说明中的功能说明不相符的错误。设计不完全错误:某些功能没有被设计,或设计得不完全。模块接口错误:模块结构不合理,模块与外部数据库以及模块之间的界面不一致。控制逻辑错误:控制流程与规格说明不一致,控制结构不合理。算法错误:算法选择不合适。数据结构错误:数据设计不合理,与算法不匹配,数据结构不满足规格说明要求。,软件测试概述,(3)编码错误 数据说明、数据使用错误。计算错、比较错。控制流错误。界面错误。输入、输出错误。其他错误。在不同的开发阶段,错误的表现形式是不同的,故应当采用不同的方法和策略来进行测试。,软件测试概述,7.1.3 软件测试的过程和策略 软件测试实践表明,软件测试是一项极其复杂而又繁重的重要工作,是保证软件质量的重要环节。软件测试的成功与否与软件测试人员的经验、知识、能力以及管理水平有关。软件测试还需遵循正确的测试过程,掌握科学的测试方法以及在测试过程中实施合理的测试策略。软件测试既是一门工程艺术,也是一种科学方法。,软件测试概述,1.软件测试的流程 软件测试是一项极其复杂的工作,它是一系列测试活动的集合,必须按照一定的测试流程,才能发现更多的错误。软件测试流程包括设计测试方案,实施测试,纠正错误,分析测试数据、建立可靠性模型等几个步骤,如图7.1所示。,软件测试概述,图7.1 软件测试的流程,软件测试概述,2.软件测试的信息流 软件测试过程中,需要3类测试信息流,如图7.2所示。图7.2 软件测试的信息流,软件测试概述,测试信息流:(1)软件配置:包括软件需求规格说明、软件设计规格说明、源代码等。(2)测试配置:包括测试计划、测试用例、测试驱动程序等。(3)测试工具:测试工具为测试的实施提供某种服务。,软件测试概述,测试之后,用测试结果与预期结果进行比较。如发现不一致的数据,就要进行纠正。对已经发现的错误进行错误定位并确定出错性质,然后纠正这些错误,同时修改相关的文档。修改后的文档一般都要经过再次测试,直到通过测试为止。通过收集和分析测试结果数据,对软件建立可靠性模型。如果测试发现不了错误,那么可以肯定测试配置考虑得不够细致充分,错误仍然潜伏在软件中。这些错误最终只能由用户在使用中发现,并在维护时由开发者去改正。但在那时改正错误的费用将比在开发阶段改正错误的费用要高出若干倍。,软件测试概述,3.测试的过程 图7.3描述了测试的过程。从图中可知,测试过程分为4个步骤,即单元测试、组装测试、确认测试和系统测试。图7.3 测试的过程,软件测试概述,首先是单元测试,根据设计的测试用例,对每个程序模块进行测试,检查每个程序模块是否正确实现了规定的功能。然后,把测试过的模块,通过组装技术,测试软件的体系结构以及实现的功能是否符合设计说明的要求。确认测试是要检查已经实现的软件能否满足需求说明规定的用户需求以及软件配置是否完全、正确。最后是系统测试,把经过确认的软件纳入实际的运行环境,与应用环境组合在一起进行测试,以检查软件能否正确、稳定地运行。测试的每个过程,都可以采用灵活的测试方法和测试策略,通常在单元测试中采用白盒测试方法,而在组装测试中采用黑盒测试方法。,7.2 软件测试用例的设计,软件测试用例的设计,7.2.1 软件测试用例和对象设计 要进行测试,除了要有测试数据外,还应同时给出该组测试数据应该得到怎样的输出结果,我们称它为预期结果。在测试时将实际输出结果与预期结果比较,若不同则表示发现了错误。因此测试用例是由测试数据和预期结果组成的。测试的目的是为了发现软件中的错误,而且发现的错误越多越好,那么是否可以把软件中隐藏的错误全部找出来呢?或者说能不能把所有可能做的测试毫无遗漏地一一做完,也就是说经过穷举测试,从而找出所有的错误呢?,软件测试用例的设计,假定一个简单程序P有输入量X和Y及输出量Z,见图7.4。在字长为32位的计算机上运行。如果X和Y只取整数,考虑把所有的X,Y值都作为测试数据,这样可能的测试数据的最大数目是 232*232=264 如果程序P测试一组数据X,Y需要1毫秒,并假定一天工作24小时,一年工作365天,要完成264 组数据测试,需要5亿年。,图7.4黑盒测试,软件测试用例的设计,以上分析表明,即使对一个算法明确的简单程序,实行穷举测试在实际上也是不可能的。因此,为了节省时间和资源,提高测试效率,就必须精心设计测试用例,也就是要从数量极大的可用测试用例中精心地选择尽量少的测试数据,使采用这些测试数据能够达到最佳的测试效果,或者说它们能够高效率地把隐藏的错误暴露出来。以上事实说明,软件测试有一个致命的缺陷,即测试的不完全、不彻底性。由于任何程序只能进行少量的有限测试,所以在发现错误时,能够说明程序有错误,在未发现错误时,也不能说明程序中没有错误,这点是必须要明确的。,软件测试用例的设计,7.2.2 黑盒测试法 黑盒测试是把程序看成是一个不透明的“黑盒子”,测试时完全不考虑程序的内部结构和处理过程,只按照规格说明书所规定的功能来设计测试用例,也就是检查程序是否符合它的功能要求。黑盒测试是在程序接口上进行的测试,又称为功能测试。常用的黑盒测试技术有等价类划分、边界值分析、错误推断法等。,软件测试用例的设计,1.等价类划分 等价类划分是用黑盒设计测试方案的一种技术。前面讲过,穷尽的黑盒测试需要使用所有有效的和无效的输入数据来测试程序,通常这是不现实的。因此,只能选取少量最具有代表性的输入数据,目的是要用较小的代价暴露出较多的程序错误。如果把所有可能的数据(有效的和无效的)划分成若干个等价类,则可以做出下述假定:每个类中的一个典型值在测试中的作用与这一类中所有其他值的作用相同。因此,可以从每个等价类中只取一组数据作为测试数据。这样选取的测试数据最具有代表性,最有可能发现程序中的错误。,软件测试用例的设计,使用等价类划分方法设计测试方案首先需要划分输入数据的等价类,为此需要研究程序的功能说明,从而确定输入数据的有效等价类和无效等价类。在确定输入数据的等价类时常常还需要分析输出数据的等价类,以便根据输出数据的等价类导出对应的输入数据等价类。,软件测试用例的设计,为了正确划分等价类,一是要注意积累经验,二是要正确分析被测程序的功能。此外,在划分无效的等价类时还必须考虑编译程序的检错功能,一般来说,不需要设计测试数据用来暴露编译程序肯定能发现的错误。最后说明一点,上面列出的启发式规则虽然都是针对输入数据说的,但是其中绝大部分也同样适用于输出数据。,软件测试用例的设计,划分出等价类以后,根据等价类设计测试方案时主要使用下面两个步骤:(1)设计一个新的测试方案,以尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步骤直到所有有效等价类都被覆盖为止。(2)设计一个新的测试方案,使它覆盖一个而且只覆盖一个尚未被覆盖的无效等价类,重复这一步骤直到所有无效等价类都被覆盖为止。注意:通常程序发现一类错误后就不再检查是否还有其他错误,因此,应该使每个测试方案只覆盖一个无效的等价类。,软件测试用例的设计,2.边界值分析 经验表明,处理边界情况时程序最容易发生错误。例如,许多程序错误出现在下标、数据结构和循环等的边界附近。因此,设计使程序运行在边界情况附近的测试方案,暴露出程序错误的可能性更大一些。使用边界值分析方法设计测试方案首先应该确定边界情况,这需要经验和创造性,通常输入等价类和输出等价类的边界,就是应该着重测试的程序边界情况。按照边界值分析方法,应该选取刚好等于、稍小于和稍大于等价类边界值的数据作为测试数据,而不是选取每个等价类内的典型值和任意值作为测试数据。设计测试方案时总是结合使用等价类划分和边界值分析两种技术。,软件测试用例的设计,3.错误推断法 使用边界值分析和等价类划分技术,可以帮助我们设计出具有代表性的,因而也就容易暴露程序错误的测试方案。但是,不同类型不同特点的程序通常又有一些特殊的容易出错的情况。此外,有时分别使用每组测试数据时程序都能正常工作,但这些输入数据的组合却可能检测出程序的错误。一般说来,即使是一个比较小的程序,可能的输入组合数也十分巨大,因此必须依靠测试人员的经验和直觉,从各种可能的测试方案中选出一些最可能引起程序出错的方案。推测程序中可能存在错误的类型,是挑选测试方案所依据的一个重要因素。,软件测试用例的设计,错误推断法在很大程度上靠直觉和经验进行,它的基本想法是列举出程序中可能有的错误和容易发生错误的特殊情况,并且根据它们选择测试方案。对于程序中容易出错的情况也有一些经验总结出来,例如,输入数据为零或输出数据为零往往容易发生错误;如果输入或输出的数目允许变化(例如,被检索的或生成的表的项数),则输入或输出的数目为0和1的情况(例如,表为空或只有一项)是容易出错的情况。此外还应该仔细分析程序规格说明书,注意找出其中遗漏或省略的部分,以便设计相应的测试方案,检测程序员对这部分的处理是否正确。,软件测试用例的设计,等价类划分方法和边界值分析方法都只是孤立地考虑各个输入数据的测试功效,而没有考虑多个输入数据的组合效应,这样可能会遗漏输入数据易于出错的组合情况。利用判定表或判定树是选择输入组合的一条有效途径,列出输入数据各种组合与程序应做的动作(即相应的输出结果)之间的对应关系,然后为判定表的每一列至少设计一个测试用例。,软件测试用例的设计,选择输入组合的另一条有效途径是把计算机测试和人工检查代码结合起来。例如,通过代码检查,发现程序中两个模块使用并修改某些共享的变量,如果一个模块对这些变量的修改不正确,则会引起另一个模块出错,这是程序发生错误的又一个可能原因。应该设计测试方案,在程序的一次运行中同时检测这两个模块,特别要着重检测一个模块修改了共享变量后,另一个模块能否像预期的那样正常使用这些变量。反之,如果两个模块相互独立,则没有必要测试它们的输入组合情况。,软件测试用例的设计,7.2.3 白盒测试法 白盒测试是把程序看成一个透明的盒子,测试人员完全了解程序的内部结构和处理过程,测试时是根据程序的内部逻辑来设计测试用例的,即检验程序中的每条路径是否都能按预定的要求正确工作。白盒测试是在程序结构上进行的测试,所以白盒测试也称为结构测试。白盒测试常用的技术是逻辑覆盖,即考察用测试数据运行被测程序时对程序逻辑的覆盖程度。主要的覆盖标准有六种:语句覆盖、判定覆盖、条件覆盖、判定.条件覆盖、条件组合覆盖和路径覆盖。为了提高测试效率,我们希望选择最少的测试用例来满足指定的覆盖标准。,软件测试用例的设计,1.语句覆盖 为了暴露程序中的错误,至少每个语句应该执行一次。语句覆盖的含义是选择足够多的测试数据,使被测程序中每个语句至少执行一次。2.判定覆盖 判定覆盖又叫分支覆盖,它的含义是不仅每个语句必须至少执行一次,而且每个判定各种可能的结果都应该至少执行一次,也就是每个判定的各个分支都至少执行一次。,软件测试用例的设计,3.条件覆盖 条件覆盖的含义是不仅每个语句至少执行一次,而且判定表达式中的每个条件都取到各种可能的结果。4.判定/条件覆盖 既然判定覆盖不一定包含条件覆盖,条件覆盖也不一定包含判定覆盖,自然会提出一种能同时满足这两种覆盖标准的逻辑覆盖,这就是判定.条件覆盖。它的含义是选取足够多的测试数据,使得判定表达式中的每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果。,软件测试用例的设计,5.条件组合覆盖 条件组合覆盖是更强的逻辑覆盖标准,它要求选取足够多的测试数据,使得每个判定表达式中条件的各种可能组合都至少出现一次。显然,满足条件组合覆盖标准的测试数据,也一定满足判定覆盖、条件覆盖和判定.条件覆盖标准。因此,条件组合覆盖是前述几种覆盖标准中最强的。但是,满足条件组合覆盖标准的测试数据并不一定能使程序中的每条路径都执行到。,软件测试用例的设计,6.路径覆盖 路径覆盖的含义是,选取足够多的测试数据,使程序的每条可能路径都至少执行一次(如果程序图中有环路,则要求每个环路至少经过一次)。路径覆盖是相当强的逻辑覆盖标准,它保证程序中每条可能的路径都至少执行一次,因此这样的测试数据更有代表性,暴露错误的能力也更强。但是,路径覆盖只是考虑到每个判定表达式的取值,并没有检验表达式中条件的各种可能组合情况。如果把路径覆盖和条件组合覆盖结合起来,可以设计出检错能力更强的测试数据。,软件测试用例的设计,7.2.4 测试实例分析 以上简单介绍了设计测试方案的几种基本方法,使用每种方法都能设计出一组有用的测试方案,但是没有一种方法能设计出全部测试方案。此外,不同方法各有所长,用一种方法设计出的测试方案可能最容易发现某些类型的错误,而对另外一些类型的错误可能不易发现。因此,对软件系统进行实际测试时,应该联合使用各种设计测试方案的方法,形成一种综合策略。通常的做法是,用黑盒法设计基本的测试方案,再用白盒法补充一些必要的测试方案。,软件测试用例的设计,具体地说,可以使用下述策略结合各种方法:(1)在任何情况下都应该使用边界值分析的方法。经验表明,用这种方法设计出的测试方案暴露程序错误的能力最强。注意,应该既包括输入数据的边界情况又包括输出数据的边界情况。(2)必要时用等价类划分法补充测试方案。(3)必要时再用错误推断法补充测试方案。(4)对照程序逻辑,检查已经设计出的测试方案。可以根据对程序可靠性的要求采用不同的逻辑覆盖标准,如果现有测试方案的逻辑覆盖程度没有达到所要求的覆盖标准,则应再补充一些测试方案。,软件测试用例的设计,应该强调指出,即使使用上述综合策略设计测试方案,仍然不能保证测试能发现一切程序错误,但是,这个策略确实是在测试成本和测试效果之间的一个合理的折中。通过前面的叙述可以看出,软件测试确实是一件十分艰巨繁重的工作。,7.3 软件测试的实施,软件测试的实施,7.3.1 单元测试 单元测试也称模块测试,是对软件最小单元的测试,也是对程序模块进行正确性检验的测试,其目的在于发现各模块内部可能存在的各种差错。通常单元测试可以放在编码阶段,程序员在编写好一个模块后,应该对自己编写的模块进行测试,检查它是否实现了详细设计说明书规定的模块功能和算法。单元测试需要从程序的内部结构出发设计测试用例,通常采用白盒测试方法。多个模块可以平行地进行单元测试。,软件测试的实施,1.单元测试的内容(1)模块接口测试:对通过被测模块的数据流进行测试。为此,对模块接口,包括参数表、调用子模块的参数、全程数据、文件输入.输出操作等都必须进行检查。(2)局部数据结构测试:设计测试用例来检查数据类型说明、初始化、缺省值等方面的问题,还要查清全局数据对模块的影响。(3)路径测试:选择适当的测试用例,对模块中重要的执行路径进行测试。对基本执行路径和循环路径进行测试可以发现大量的路径错误。,软件测试的实施,(4)错误处理测试:检查模块的错误处理功能是否包含有错误或缺陷。例如:是否拒绝不合理的输入,出错的描述是否难以理解,是否对错误定位有误,是否对出错原因报告有误,是否对错误条件的处理有误,在对错误处理之前错误条件是否已经引起系统的干预,等等。(5)边界测试:要特别注意数据流、控制流中刚好等于、大于或小于确定的比较值时出错的可能性。对这些地方要仔细地选择测试用例,认真加以测试。此外,如果对模块运行时间有要求的话,还要专门进行关键路径测试,以确定最坏情况下和平均意义下影响模块运行时间的因素。这类信息对于性能评价是十分有用的。,软件测试的实施,2.单元测试的步骤 通常单元测试在编码阶段进行。在源程序代码编制完成,经过评审和验证,确认没有语法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,可以设计出验证程序功能,找出程序错误的多个测试用例。对于每一组测试用例,应有预期的正确结果。模块并不是一个绝对独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些辅助模块去模拟与被测模块相联系的其他模块。这些辅助模块有驱动模块和桩模块。,软件测试的实施,(1)驱动模块:相当于被测模块的主程序。用它接收测试用例的测试数据,把这些数据传送给被测模块,最后输出测试结果。(2)桩模块(也称连接模块):用以代替被测模块所调用的子模块。桩模块可以做少量的数据操作,不需要把子模块的所有功能都带进来,但不允许什么事情也不做。,软件测试的实施,被测模块、相关的驱动模块和桩模块共同构成了一个“测试环境”,如图7.6所示。,图7.6 单元测试的测试环境,软件测试的实施,为了进行单元测试必须编写测试软件,但是通常并不把它们作为软件产品的一部分交给用户。许多模块不能用简单的测试软件充分测试,为了减少开销可以使用下面将要介绍的渐增式测试方法,在组装测试的过程中同时完成对模块的详尽测试。模块的内聚程度直接影响单元测试的测试过程,显然,高内聚的模块设计将会明显减少设计测试用例的数目,也更容易预测和发现模块中的错误。,软件测试的实施,7.3.2 组装测试 组装测试也称集成测试,是在单元测试的基础上,将所有模块按照软件设计要求组装成为系统并进行测试的过程。组装测试主要通过检查模块间的结构和通信发现软件设计阶段产生的错误,通常采用黑盒测试方法。在组装测试过程中,需要考虑如下几个问题:在把各个模块连接起来的时候,穿越模块接口的数据是否会丢失。一个模块的功能是否会对另一个模块的功能产生不利的影响。各个子功能组合起来,能否达到预期要求的父功能。全局数据结构是否有问题。,软件测试的实施,单个模块的误差累积起来,是否会放大,以至于达到不能接受的程度。单个模块的错误是否会导致数据库错误。选择什么方式把模块组装起来形成一个可运行的系统,直接影响到测试用例的形式、测试工具的类型、模块编号的次序和测试的顺序以及生成测试用例的费用和调试的费用。通常把模块组装成为系统的方式有两种。,软件测试的实施,1.非渐增式组装方式 这种组装方式也叫做整体拼装。使用这种方式,首先对每个模块分别进行模块测试,然后再把所有模块组装在一起进行测试,最终得到要求的软件系统。由于程序中不可避免地存在涉及模块间接口、全局数据结构等方面的问题,所以一次试运行成功的可能性并不是很大。,软件测试的实施,2.渐增式组装方式 渐增式组装方式也称增殖式方式。这种方式是将单元测试和组装测试合并在一起使用,根据模块结构图,按某种次序选一个尚未测试的模块,把它同已经测试好的模块组合在一起进行测试,每次增加一个模块,直至所有模块全部组装在系统中。在组装的过程中边连接边测试,以便发现连接过程中产生的问题,通过这种方法可以逐步组装成为满足要求的软件系统。渐增式组装方式有两种:自顶向下和自底向上的增殖组装方式。,软件测试的实施,7.3.3 确认测试 组装测试已经按照设计把所有模块组装成一个完整的软件系统,接口错误也已经基本排除了,接着就应该进一步验证软件的有效性,即验证软件的功能、性能及其他特性是否与用户的要求一致。这就是确认测试。在软件需求规格说明书中描述了全部用户可见的软件属性,其中有一节叫做有效性准则,它包含的信息就是软件确认测试的基础。通过有效性测试以及软件配置复查和安装测试,然后通过专家鉴定,才能成为可交付使用的软件。,软件测试的实施,1.有效性测试 有效性测试是在模拟的环境(可能就是开发的环境)下,运用黑盒测试的方法,验证被测软件是否满足需求规格说明书所列出的需求。为此,需要首先制定测试计划,规定所做测试的种类。还需要制定一组测试步骤,描述具体的测试用例。通过实施预定的测试计划和测试步骤,确定软件的特性是否与需求相符,确保所有的软件功能需求都能得到满足,所有的软件性能需求都能达到,所有的文档都是正确且便于使用的。同时,对软件其他需求,例如可移植性、兼容性、出错自动恢复、可维护性等,也都要进行测试,确认是否满足要求。,软件测试的实施,2.软件配置复查 软件配置复查的目的是保证软件配置的所有成分都齐全,各方面的质量都符合要求,具有维护阶段所必需的细节,而且已经编排好分类的目录。除了按合同的内容和要求,由人工审查软件配置之外,在确认测试的过程中,应当严格遵守用户手册和操作手册中规定的使用步骤,不能以“做一日和尚撞一天钟”的态度来检查这些文档资料的完整性和正确性,必须仔细记录发现的遗漏和错误,并且适当地加以补充和改正。,软件测试的实施,3.测试和测试 在软件交付使用之后,用户将如何实际使用程序,对于开发者来说是无法预测的。因为用户在使用过程中常常会对使用方法产生误解,使用异常的数据组合以及产生对某些用户来说似乎是清晰的但对另一些用户来说却是难以理解的输出等。如果软件是为多个用户开发的,那么让每个用户逐个执行正式的验收测试是不切实际的。因此很多软件产品生产者采用一种称之为测试和测试的测试方法,以发现可能只有最终用户才能发现的错误。,软件测试的实施,测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的测试。测试是在受控制的环境下进行的。测试的目的是评价软件产品的功能,如可使用性、可靠性和支持性等性能,尤其注重产品的界面和特色。测试人员是除了产品开发人员之外首先见到产品的人,他们提出的功能要求和修改意见是特别有价值的。测试可以从软件产品编码结束之时,或是模块(子系统)测试完成之后开始,也可以在测试过程中确认产品达到一定的稳定和可靠程度之后再开始。,软件测试的实施,测试是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。与测试不同的是,开发者通常不在测试现场。因而,测试是在开发者无法控制的环境下进行的软件现场应用。在测试中,由用户记下遇到的所有问题,包括真实的以及主观认定的,定期向开发者报告,开发者在分析用户的报告之后,修正软件错误,并最终将软件产品发布给全体用户使用。测试着重于产品的支持性,包括文档、客户培训和支持产品生产能力。只有当测试达到一定的可靠程度时,才能开始测试。,软件测试的实施,由于它处在整体测试的最后阶段,所以不能指望这时发现主要问题。同时产品的所有手册文本也应该在此阶段完全定稿。由于测试的主要目标是测试可支持性,所以测试应尽可能由主持产品发行的人员来管理。确认测试把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似。但是,它是在用户的积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的数据)进行测试。确认测试的目的是验证系统确实能够满足用户的需要,在这个测试步骤中发现的错误往往是系统需求说明书中的错误。,软件测试的实施,4.验收测试 在通过了系统的有效性测试及软件配置复查之后,接下来进行系统的验收测试。验收测试是以用户为主的测试,同时软件开发人员和QA(Quality Assurance,质量保证)人员也应参加。由用户参与设计测试用例,使用用户界面输入测试数据,并分析测试的输出结果,一般使用生产中的实际数据进行测试。在测试过程中,除了考虑软件的功能和性能外,还应对软件的可移植性、兼容性、可维护性、错误的恢复功能等进行确认。,软件测试的实施,5.确认测试结果 在全部确认测试的测试用例运行完后,所有的测试结果可以分为两类:(1)测试结果与预期的结果相符,这说明软件的这部分功能或性能特征与需求说明书相符合,从而这部分程序可以接受。(2)测试结果与预期的结果不符,这说明软件的这部分功能或性能特征与需求说明书不一致,因此需要开列一张软件各项缺陷表或软件问题报告,通过与用户的交流,解决所发现的缺陷和错误。,软件测试的实施,7.3.4 系统测试 所谓系统测试,是将通过确认测试的软件作为基于整个计算机系统的一个元素,与计算机硬件、外设、某些支持软件、数据和人员等其他系统元素结合在一起,在实际运行环境下,对计算机系统进行一系列的组装测试和确认测试。系统测试的目的在于通过与系统的需求说明做比较,发现软件与系统定义不符合或相矛盾的地方。系统测试的测试用例应根据需求说明书来设计,并在实际运行环境中运行。,软件测试的实施,7.3.5 软件纠错 测试是找出软件外部的错误,纠错是在测试出错的基础上分析错误的性质与原因,找出出错的位置,即找到内部错误,再加以纠正,直到测试没有错误为止。概括地说,这种根据测试发现错误的外因,通过分析找到错误的内部原因并加以改正的人工活动称为纠错。,软件测试的实施,1.纠错的步骤 纠错作为测试的后继工作,应该按照一定的步骤来进行。(1)从错误的外部表现形式入手,确定程序出错位置。(2)研究有关部分的程序,找出错误的内在原因。(3)修改设计和代码,以排除这个错误。(4)重复使用暴露这个错误的原始测试数据测试或某些有关测试,以确认该错误是否被排除以及是否引进了新的错误。(5)如果所做的修正无效,则撤销这次改动,重复上述过程,直到找到一个有效的解决方法为止。,软件测试的实施,2.纠错方法(1)强行纠错法 强行纠错法是通过系统的调试跟踪工具,将信息打印或显示出来,逐一地查找错误的原因,并进行纠错的过程。这是一种很普遍的使用方法,但效率比较低,而且缺乏系统的分析过程。,软件测试的实施,(2)回溯法纠错 采用回溯法纠错时,首先分析错误征兆,确定最先发现“症状”的位置。然后沿程序的控制流程,回溯跟踪源程序代码,直到找到错误根源或确定错误产生的范围为止。例如,程序中发现错误的地方是某个打印语句。通过输出值可推断出程序在这点上的变量值,再从这一点出发,回溯程序的执行过程,反复考虑“如果程序在这点上变量的值是这样,那么程序在上一点上变量的值应该是这样”,直到找到错误的位置,即在其状态是预期的点与第一个状态不是预期的点之间的程序位置。实践证明,回溯法对小程序是很有效的纠错方法。通过回溯,往往能把错误范围缩小到程序中的一小段代码,仔细分析这段代码不难确定错误的准确位置。但对于大程序,由于回溯的路径数目较多,回溯会很困难。,软件测试的实施,归纳的思考过程是从特殊到一般,从对个别事物的认识当中,通过抽象概括出事物的共同特点,得出一般性的规律的过程。归纳法就是从线索(错误征兆)出发,通过分析这些线索之间的关系而找出错误的一种系统化的思考方法。归纳法包括下述四个步骤,收集相关数据、组织数据、提出假设、证明假设。,软件测试的实施,(4)演绎法纠错 演绎法是一种从一般原理或前提出发,经过排除和精确化的过程推导出结论的思考方法。演绎法是测试人员首先根据已有的测试用例,设想及枚举出所有可能的出错原因作为假设,然后再用原始测试数据或新的测试数据,逐个排除不可能正确的假设,最后再用测试数据验证余下的假设的确是出错的原因。演绎法有以下四个步骤,如图7.10所示。,排除不当原因,推断保留假设,证明假设,枚举可能原因,收集更多数据,纠正错误,有剩余,无剩余,不能,能,图7.10 演绎法纠错过程,7.4 软件测试的面向对象方法简述,软件测试的面向对象方法简述,面向对象技术是一种全新的软件开发技术,正逐渐代替被广泛使用的面向过程的开发方法,被看成是解决软件危机的新兴技术。面向对象技术能产生更好的系统结构,更规范的编程风格,极大地优化了数据使用的安全性,提高了程序代码的可重用性。应该看到,尽管面向对象技术的基本思想保证了软件应该有更高的质量,但实际情况却并非如此,因为无论采用什么样的编程技术,编程人员的错误都是不可避免的,而且由于面向对象技术开发的软件代码重用率高,更需要严格测试,避免错误的繁衍。所以,软件测试并没有因为面向对象编程的兴起而丧失它的重要性。,软件测试的面向对象方法简述,7.4.1 面向对象测试的基本概念 面向对象程序的结构不再是传统的功能模块结构,作为一个整体,原有组装测试所要求的逐步将开发的模块搭建在一起进行测试的方法已成为不可能。而且,面向对象软件抛弃了传统的开发模式,对每个开发阶段都有不同于以往的要求和结果,所以也不可能用功能细化的观点来检测面向对象分析和设计的结果。因此,传统的测试模型对面向对象软件已经不再适用。针对面向对象软件的开发特点,应该有一种新的测试模型。,软件测试的面向对象方法简述,1.面向对象测试模型 面向对象的开发模型突破了传统的瀑布模型,将开发分为面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)三个阶段。分析阶段产生整个问题空间的抽象描述,在此基础上,进一步归纳出适用于面向对象编程语言的类和类结构,最后形成代码。由于面向对象的特点,采用这种开发模型能有效地将分析设计的文本或图表代码化,不断适应用户需求的变动。针对这种开发模型,结合传统的测试步骤的划分,在开发过程中不断地进行测试,使开发阶段的测试与编码完成后的单元测试、组装测试、系统测试成为一个整体。,软件测试的面向对象方法简述,2.面向对象分析的测试(OOA Test)OOA直接映射问题空间,将问题空间中实现的功能抽象化。将问题空间中的实例抽象为对象(不同于C+中的对象概念),用对象的结构反映问题空间的复杂实例和复杂关系,用属性和服务表示实例的特性和行为。OOA的结果是为后面阶段中类的选定和实现以及类层次结构的组织和实现提供平台。因此,如果OOA对问题空间的分析抽象不完整,则会影响软件的功能实现,导致软件