试情况,以及使输出强迫为0的测试情况。
例如,要测试一个排序子程序,特别需要检查的情况是:输入表为空;输入表只含有一个元素;输入表的所有元素的值都相同;输入表已经排过序。这些情况都在程序设计时可能忽略的特殊情况。
实际上,无论是使用白盒测试方法还是黑盒测试方法,或是其他测试方法,针对一种方法设计的测试用例,仅仅是易于发现某种类型的错误,对其他类型的错误不易发现,所以没有一种用例设计方法能适应全部的测试方案,而是各有所长,综合使用各种方法来确定合适的测试方案,应该考虑在测试成本和测试效果之间的一个合理折中。 四、 软件测试的实施
软件测试是保证软件质量的重要手段,软件测试是一个过程,其测试流程是该过程规定的程序,目的是使软件测试工作系统化。
软件测试过程一般按4个步骤进行,即单元测试,集成测试、验收测试(确认测试)和系统测试。
通过这些步骤的实施来验证软件是否合格,能否交付用户使用。 1、 单元测试
单元测试是对软件设计的最小单位——模块(程序单元)进行正确性检验的测试。单元测试的目的是发现各模块内部可能存在的各种错误。 单元测试的依据是详细设计说明书和源程序。 单元测试的技术可以采用静态分析和动态测试。对动态测试通常以白盒动态测试为主,辅之以黑盒测试。
单元测试主要针对模块的下列5个基本特性进行: ① 模块接口测试——测试通过模块的数据流。例如,检查模块的输入参数和输出参数、全局量、文件属性与操作等都属于模块接口测试的内容。 ② 局部数据结构测试。例如,检查局部数据说明的一致性,数据的初始化,数据类型的致以及数据的下溢、上溢等。 ③ 重要的执行路径的检查。 ④ 出错处理测试。检查模块的错误处理功能。 ⑤ 影响以上各点及其他相关点的边界条件测试。 单元测试是针对某个模块,这样的模块通常并不是一个独立的程序,因此模块自己不能运行,而要靠辅助其他模块调用或驱动。同时,模块自身也会作为驱动模块去调用其他模块,也就是说,单元测试要考虑它和外界的联系,必须在一定的环境下进行,这些环境可以是真实的也可以是模拟的。模拟环境是单元测试常用的。
所谓模拟环境就是在单元测试中,用一些辅助模块去模拟与被测试模块的相联系的其他模块,即为被测模块设计和搭建驱动模块和桩模块。
其中,驱动模块相当于被测模块的主程序。它接收测试数据,并传给被测模块,输出实际测试结果。桩模块通常用于代替被测模块调用的其他模块,其作用仅做少量的数据操作,是一个模拟子程序,不必将模块的所有功能带入。 2.集成测试
集成测试是测试和组装软件的过程。它是把模块在按照设计要求组装起来的同时进行测试,主要目的是发现与接口有关的错误。集成测试的依据是概要设计说明书。
集成测试所涉及的内容包括:软件单元的接口测试、全局数据结构测试、边界条件和非法输入的测试等。
集成测试时效模块组装成程序通常采用两种方式:非增量方式组装与增量方式组装。 非增量方式也称为一次性组装方式。将测试好的每一个软件单元一次组装在一起再进行整体
测试。
增量方式是将已经测试好的模块逐步组装成较大系统,在组装过程中边连接边测试,以发现连接过程中产生的问题。最后通过增殖,逐步组装至所要求的软件系统。
增量方式包括自顶向下、自底向上、自顶向下与自底向上相结合的混合增量方法。 (1) 自顶向下的增量方式
将模块按系统程序结构,从主控模块(主程序)开始,沿控制层次自顶向下地逐个把模块连接起来。自顶向下的增量方式在测试过程中能较早地验证主要的控制的判断点。 自顶向下集成的过程与步骤如下: ① 主控模块作为测试驱动器。直接附属于主控模块的各模块全都用桩模块代替。 ② 按照一定的组装次序,每次用一个真模块取代一个附属的桩模块。 ③ 当装入每个真模块时都要进行测试。 ④ 做完每一组测试后再用一个真模块代替另一个桩模块。 ⑤ 可以进行回归测试(即重新再做过去做过的全部或部分测试),以便确定没有新的错误发生。
例3.7对图3。30(A)所示程序结构进行自顶向下的增量方式组装测试。 自顶向下的增量方式的组装过和如图3。30(B)~(F)所示 (2) 自底向上的增量方式
自底向上集成测试方法是从软件结构中最底层的、最基本的软件单元开始进行集成和测试。在模块的测试过程中需要从子模块得到的信息可以直接运行子模块得到。由于在逐步向上组装过程中下层模块总是存在的,因此不再需要桩模块,但是需要调用这些模块的驱动模块。 自底向上集成的过程与步骤如下: ① 低层的模块组成簇,以执行某个特定的软件子功能。 ② 编写一个驱动模块作为测试的控制程序,和被测试的簇连在一起,负责安排测试用例的输入及输出。 ③ 对簇进行测试。 ④ 拆去各个小簇的驱动模块,把几个小簇合并成大簇,再重复做2。3。4步。这样在软件结构上逐步向上组装。
例3.8对图3。31(A)所示程序结构进行自底向上的增量方式的组装测试。 自底向上的增量方式的组装过程如图3。31(B)至(D)所示。 (3) 混合增量方式
自顶向下增量的方式和自底向上增量的方式各有优缺点,一种方式的优点是另一种方式的缺点。
被测程序(A) 加入A 加入B 加入E
加入C 加入D 自顶向下的增量测试
自底向上的增量测试
自顶向下测试的主要优点是能较早显示出整个程序的轮廓,主要缺点是,当测试上层模块时使用桩模块较多,很难模拟出真实模块的全部功能,使部分测试内容被迫推迟,直至换上真实模块后再补充测试。
自底向上测试从下层模块开始,设计测试用例比较容易,但是在测试的早期不能显示出程序的轮廓。
针对自顶向下、自底向上方法各自的优点和不足,人们提出了自顶向下的自底向上相结合、从两头向中间逼近的混合式组装方法,被形象称之为“三明治”方法。这种方式,结合考虑软件总体结构的良好设计原则,在程序结构的高层使用自顶向下方式 ,在程序结构的低层使用自底向上方式。 3.确认测试
确认测试的任务是验证软件功能和性能及其他特性是否满足了需求规格说明中确定的各种需求,以及软件配置是否完全、正确。 确认测试的实施首先运用黑盒测试方法,对软件进行有效性测试,即验证被测试软件是否满足需求规格说明确认的标准。复审的目的在于保证软件配置齐全、分类有序,以及软件配置所有成分的完备性、一致性、准确性和可操作性,并且包括软件维护所必需的细节。 4、系统测试
系统测试是将通过测试确认的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、支持软件、数据和人员等其他系统元素组合在一起,在实际运行(使用)环境下对计算机系统进行一系列的集成测试和确认测试。由此可知,系统测试必须在目标环境下运行,其功用在于评估系统环境下软件的性能,发现和捕捉软件中潜在的错误。
系统测试的目的是在真实的系统工作环境下检验软件是否能与系统正确连接,发现软件与系统需求不一致的地方。
系统测试的具体实施一般包括:功能测试、性能测试、操作测试、配置测试、外部接口测试、安全性测试等。 3.5程序的调试 一、基本概念
在对程序进行了成功的测试之后将进入程序调试(通常称Debug,即排错)。程序调试的任务是诊断和改正程序中的错误。它与软件测试不同,软件测试是尽可能多地发现软件中的错误。先要发现软件的错误,然后借助于一定的调试工具去执行找出软件错误的具体位置。软件测试贯穿整个软件生命期,调试主要在开发阶段。 由程序调试的概念可知,程序调试活动由两部分组成,其一是根据错误的迹象确定程序中错误的确切性质、原因和位置。其二,对程序进行修改,排除这个错误。 1、 程序调试的基本步骤 (1) 错误定位
从错误的外部表现形式入手,研究有关部分的程序,确定程序中出错位置,找出错误的内在原因。确定错误位置占据了软件调试绝大部分的工作量。 从技术角度来看,错误的特征和查找错误的难度在于: ① 现象与原因所处的位置可能相距很远。就是说,现象可能出现在程序的一个部位,而原因可能在离此很远的另一个位置。高耦合的程序结构中这种情况更为明显。 ② 当纠正其他错误时,这一错误所表现出的现象可能会消失或暂时性消失,但并未实际排除。 ③ 现象可能并不是由错误引起的(如舍入误差)。 ④ 现象可能性是由于一些不容易发现的人为错误引起的。 ⑤ 错误现象可能时有时无。 ⑥ 现象是由于难于再现的输入状态(例如实时应用中输入顺序不确定)引起的。 ⑦ 现象可能是周期出现的。
(2) 修改设计和代码,以排除错误 排错是软件开发过程中一项艰苦的工作,这也决定了调试工作是一个具有很强技术性和技巧性的工作。软件工程人员在分析测试结果的时候会发现,软件运行失效或出现问题,往往只是潜在错误的外部表现,而外部表现与内在原因之间常常没有明显的联系。如果要找出真正的原因,排除潜在的错误,不是一件易事。因此可以说,调试是通过现象,找出原因的一个思维分析的过程。
(3) 进行回归测试,防止引进新的错误 因为修改程序可能带来新的错误,重复进行暴露这个错误的原始测试或某些有关测试,以确认该错误是否被排除、是否引进了新的错误。如果所做的修正无效,则撤销这次改动,重复上述过程,直到找到一个有效的解决办法为止。 2、 程序调试的原则 在软件调试方面,许多原则实际上是心理学方面的问题。因为调试活动由对程序中错误的定性,定位和排错两部分组成,因此调试原则 也从以下两个方面考虑。 (1) 确定错误的性质和位置时的注意事项: ① 分析思考与错误征兆有关的信息。 ② 避开死胡同。 ③ 只把调试工具当作辅助手段来使用。 ④ 避免用试探法,最多只能把它当作最后手段。
(2) 修改错误的原则 ① 在出现错误的地方,很可能还有别的错误。经验表明,错误吸群集现象,当在某一程序段发现有错误时,在该程序段中还存在另的错误的概率也很高。因此,在修改一个错误时,还要观察和检查相关的代码,看是否还有别的错误。 ② 修改错误的一个觉失误是只修改了这个错误的征兆或这个错误的表现,而没有修改错误本身。如果提出的修改不能解释与这个错误有关的全部现象,那就表明了只修改了错误的一部分。 ③ 注意修正了一个错误的同时有可能会引入新的错误。 ④ 修改错误的过程将迫使人们暂时回到程序设计阶段。修改错误也是程序设计的一种形式。一般说来,在程序设计阶段所使用的任何方法都可以应用到错误修正的过程中来。 ⑤ 修改源代码程序,不要改变目标代码。 二、软件调试方法
调试的关键在于推断程序内部的错误位置及原因。从是否跟踪和和执行程序的角度,类似于软件测试,软件调试可以分为静态调试和动态调试。软件测试中讲座的表态分析方法同样适用静态调试。静态调试主要指通过人的思维来分析源程序代码和排错,是主要的调试手段,而动态调试是辅助静态调试的。主要的调试方法可以采用: 1、强行排错法 ① 通过内存全部打印来排错。 ② 在程序特定部位设置打印语句——即断点法。输出存储器内容,就是在程序执行到某一行的时候,计算机自动停止运行,并保留这时各变量的状态,方便检查,校对。 ③ 自动调试工具。其功能是设置断点,当程序执行到某个特定的语句或某个特定的变量值改变是地,程序暂停执行。程序可在终端上观察程序此时的状态。 应用以上任何一种技术之前,都应当对错误的征兆进行全面彻底的分析,得出对出错位置及错误性质的推测,再使用一种适当的排错方法来检验推测的正确性。 2、回溯法
该方法适合于小规模程序的排错。即一旦发现了错误,先分析错误征兆,确定最先发现“症状”的位置。然后,从发现“症状”的地方开始,沿程序的控制流程,逆向跟踪源程序代码,直到找到错误根源或确定错误产生的范围。 3、 原因排除法
原因排除法是通过演绎和归纳,以及二分法来实现的。 演绎法是一种从一般原理或前提出发,经过排除和精化的过程来推导出结论的思考方法。演绎法排错是测试人员首先根据已有的测试用例,设想及枚举出所有可能出错的原因作为假设。然后再用原始测试数据或新的测试,从中逐个排除不可能正确的假设。最后,再用测试数据验证余正气假设确定出错的原因。
归纳法是一种从特殊扒断出一般的系统化思考方法。其基本思想是从一些线索(错语征兆或与错误发生有关的数据)着手,通过分析寻找到潜在的原因,从而找出错误。 二分法实现的基本思想是,如果已知每个变量在程序中若干个关键点的正确值,则可以使用宣传语句(如赋值语句、输入语句等)在程序中的某点附近给这些变量赋正确值,然后运行程序并检查程序的输出。如果输出结果是正确的,则错误原因在程序的前半部分;反之,错误原因在程序的后半部分。对错误原因所在的部分重复使用这种方法,直到将出错范围缩小到容易诊断的程序为止。
需要注意的一个实际问题是,调试的成果是排错,为了修改程序中错误,往往会采用“补丁程序”来实现,而这种做法会引起整个程序质量的下降,但是从目前程序设计发展的状况看,对大规模的程序的修改和质量保证,又不失为一种可行的方法。