您现在所在的位置是:首页 > 业界新闻

软件公司常见软件测试技术

3.1测试用例

测试用例是为特定的目的而设计的一组测试输入、执行条件和预期的结果,是执行的最小实体。简单地说,测试用例就是设计一个场景,使被

测程序在这种场景下,必须能够正常运行并且达到程序所设计的执行结果。

3.1.1测试用例设计原则

测试用例的设计是软件测试人员的工作核心,它的设计必须符合以下原则:

(1)测试用例设计要基于需求:必须按照不同的测试级别的要求,设计测试用例。如单元测试依据详细的设计说明,集成测试依据概要设计说明

书,等等。

(2)测试用例设计要基于测试方法:必须指明采用的用例设计方法。为了达到不同的测试覆盖率,要采用相应的测试方法,如等价类划分、边界

值分析、正交分析和决策表等具体方法。

(3)测试用例必须具有代表性:能够代表并覆盖各种合理的和不合理的、合法的和非法的、边界的和越界的以及极限的输人数据、操作和环境设

置等。

(4)测试用例必须具有可执行性:每个用例必须有详细的执行步骤。

(5)一个用例只能针对一个问题:同时覆盖多个测试点,会导致Bug定位困难。

(6)测试结果必须具有可判定性:即测试执行结果的正确性是可判定的,每一个测试用例都应有相应的期望结果。

(7)测试结果必须具有可再现性:即对同样的测试用例,系统的执行结果应当是相同的。

(8)兼顾测试的充分性和效率:设计测试用例必须权衡分析的覆盖率和时间上的可操作性。

3.1.2测试用例的描述

ANSI/IEEE829标准中罗列了测试用例描述所应包含的信息:

(1)标识符。由测试设计过程说明和测试程序说明引用的唯一标识符。

(2)测试项。描述被测试的详细特性、代码模块等,应该比测试设计说明中所列的特性更加具体。如果测试设计说明指出“计算器程序的加法功

能”,那么测试用例说明就会详细描述为“加法运算的上溢处理”。

(3)输入说明。该说明列举测试用例的输入内容或条件。如果测试计算器程序,输入说明可能是1+1。

(4)输出说明。该说明用以描述程序执行结果,例如1+1—2吗?

(5)环境要求。用以描述执行测试案例必要的硬件、软件、测试工具、人员等等。

(6)特殊要求。描述执行测试必须做到的特殊要求。如航天航空导航系统的特殊要求。

(7)测试用例之间的依赖。一个测试用例依赖于其他用例,那么它的执行结果会受到其他用例的影响,在此应予以注明。

如果严格按照上述要求编纂文档,那么一个仅有数千个用例的小项目就会形成数千页的文档,编写完文档,项目就已经耽误了。所以应简化文

档。虽然描述测试用例的结构和标准会随着软件组织的不同而有区别。但是有一点非常重要,就是测试用例中至少要包括测试输入条件、执行

条件和相应的预期结果这3项内容。表3—1给出了用自然语言描述的测试用例的一个简单示例。

3.1.3测试用例的执行

执行测试用例,获取测试结果,并根据判定结果采取相应的措施。当测试过程正常终止时,对执行结果进行核对,若结果准确无误,则结束该

测试用例。当测试过程异常终止时,对执行结果进行核对,记录相关内容,并决定是否修改和补充测试用例集合。

测试执行主要可以分为两个周期:一个是测试周期,另一个是错误报告周期。

测试周期包括了测试用例执行的几个状态:等待、执行、阻塞、通过、失败和关闭。

等待状态是指测试用例已经设计完成并等待适当的时候进行执行,测试用例未能得到立即执行的原因通常是用例的全部条件没有达到,例如其

前置条件没有满足,或者测试环境尚未搭建完成。而引起阻塞的原因通常是执行其他用例时触发的错误,使得当前的用例无法执行.例如一个

程序的主界面无法打开,那么在主界面上执行操作的用例就被阻塞了。执行测试之后的结果有3种,一种是通过,一种是错误,一种是无法验证

。通过即是运行结果与预期相同,错误则是与预期结果不一致,而无法验证通常是由测试用例设计问题引起的,例如用例中对结果表述不清,

结果描述使用一些带有主观色彩的词汇(诸如:正确、美观之类),等等。

总之,测试周期中,测试的执行过程就是安排测试用例、运行测试用例、分析测试用例、修改完善测试用例这几个环节的循环过程。

错误报告周期则包含了寻找错误、触发错误、记录错误、定位错误、修改错误和确认修复成功等环节。设计测试用例的过程其实就是一个寻找

错误的过程,而运行测试用例就是一个触发错误的过程,当运行结果与预期不同时,就记录下了一跳错误,随后将定位和修复错误,并作最后

的确认工作。

无论是哪一种测试的执行过程,都不是一个单调的顺序过程,都需要迭代和循环。从理论上讲,每修改一个软件中的错误,软件就会回到测试

前的状态,这就需要重新对软件进行全面的测试。实际工程中可能没有要求如此严苛,但是也要对修复问题所影响的模块进行彻底的全面测试

。而测试工作本身即是一个循环往复的过程,这就是测试充分性在测试理论中有其特殊地位的原因。

选择首先执行哪些测试用例是一个极具策略性的决定,它取决于对软件质量的要求、可供使用的资源、现有的测试文档和风险评估结果的综合

分析。执行测试的重点放在高风险特征项目上。

3.1.4测试用例的组织和跟踪

为了组织和跟踪测试用例的方便,工程中通常使用表格或者数据库来管理测试文档。中小型项目中,使用表格是跟踪测试用例非常流行和奏效

的方法。数字表格保存了测试用例的所有细节,这大大减轻了测试人员的文档工作量,同时也使得项目的测试状态一目了然。在大型项目中,

则需要使用数据库来协助管理测试文档,以免使测试人员陷入测试文档的汪洋大海之中。表3—2是一个Android播放器的测试用例。表3—3是该

测试用例的统计表,由表3—2生成。

3.2功能性测试

功能性测试又称黑盒测试、数据驱动测试或基于规格说明的测试,是一种从用户观点出发的测试。用这种方法进行测试时,测试人员把被测程

序或系统当做一个黑盒,不考虑程序或系统是怎样工作的,只侧重于根据规约去测试程序或系统功能的正确性和可操作性。功能性测试的主要

目标是发现以下类型的错误:

(1)不正确或遗漏的功能。

(2)数据结构或外部数据库访问错误。

(3)性能错误。

(4)初始化或终止错误。

功能性测试在设计测试用例时只对输入和输出进行考虑。但由于时间和资源有限,对所有可能的输入进行穷尽测试是不现实的,因此测试人员

的目标就是在可用资源下生成测试用例,以能够找到尽可能多的错误。常用的黑盒测试技术包括等价类划分、边界值分析、正交分析法和决策

表,下面对这些技术逐一进行介绍。

3.2.1等价类划分
等价类划分就是将所有可能的输入数据划分成若干个等价类,然后在每一个等价类中选取少数具有代表性的数据作为测试数据。

等价类是指程序输入域的某个互不相交的子集,该子集中的每个输入数据对揭露软件中的错误都是等效的,测试等价类的某个代表值就等价于

对这一类其他值的测试。而且所有等价类的并便是整个输入域。

等价类可分为有效等价类和无效等价类。有效等价类是指符合规格说明要求的合理的输入数据集合。主要用来检验程序是否实现了规格说明预

先规定的功能和性能。无效等价类是指不符合规格说明要求的不合理的或非法的输人数据集合,主要用来检验程序是否做了不符合规格说明要

求的事。

在确定输入数据等价类时,常常还要分析输出数据的等价类,设计完整的测试用例。
1.等价类划分方法设计测试用例
(1)确定等价类。在遇到实际问题时,可参照下列规则的思想来划分等价类:
1)如果输入条件规定了取值范围或值的个数,则可以确定一个有效等价类和两个无效等价类。
2)如果输入条件规定了输入值的集合(离散型),而且程序对不同的输入作不同的处理,那么每个允许的值都确定为一个有效等价类,另外还有

一个无效等价类。
3)如果输入条件规定了输入值必须遵循的规则,那么可以确定一个有效等价类(符合此规则)和若干个无效等价类(从不同角度违反此规则)。
4)如果输人条件规定输入数据是整型,则可确定3个有效等价类(正整数、零、负整数)和一个无效等价类(非整数)。
5)如果输入条件规定处理对象是表格,那么可以确定1个有效等价类(表中一项或多项数据)和1个无效等价类。
(2)利用等价类来设计测试用例。在设计测试用例时应同时考虑有效等价类和无效等价类测试用例的设计。根据等价类表设计测试用例,具体步

骤如下:
1)为每个等价类规定一个唯一的编号。
2)设计一个新的测试用例,尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步.直到测试用例覆盖了所有的有效等价类。
3)设计一个新的测试用例,使其覆盖并且只覆盖一个还没有被覆盖的无效等价类。重复这一步,直至测试用例覆盖了所有的无效等价类。
3.等价类测试存在的问题
(1)规格说明往往没有定义无效测试用例的期望输出。因此,测试人员需要花费大量时间来定义这些测试用例的期望输出。
(2)强类型语言没有必要考虑无效输入。传统等价类测试是诸如FORTRAN和C()BoL这样的语言占统治地位年代的产物,那时这种无效输入的故障

很常见。事实上,正是由于经常出现这种错误,才促使人们使用强类型语言。

3.2.2边界值分析大量的软件测试实践表明,故障往往出现在定义域或值域的边界上,而不是在其内部。为检测边界附近的处理专门设计测试

用例,通常都会取得很好的测试效果。因此边界值分析法是一种很实用的功能性测试的方法,它具有很强的发现软件缺陷的能力。
1.边界条件
边界条件就是软件计划的操作界限所在的边缘条件。边界条件是一些特殊情况,程序在处理大量中间数值时都正确。但是在边界处可能出现错

误。
一些可能与边界有关的数据类型有数值、速度、字符、地址、位置、尺寸、数量等。相应地,边界问题考虑这些数据类型的下述特征:第一个

/最后一个,最小值/最大值,开始/完成,超过/在内,空/满,最短/最长,最慢/最快,最早/最迟。最高/最低,相邻/最远等。其

实,边界值和等价类密切相关,输入等价类和输出等价类的边界是要着重测试的边界情况。在等价类的划分过程中产生了许多等价类边界。边

界是最容易出错的地方,所以,从等价类中选取测试数据时应该关注边界值。
在等价类划分基础上进行边界值分析测试的基本思想是,选取正好等于、刚刚大于或刚刚小于等价类边界的值作为测试数据,而不是选取等价

类中的典型值或任意值作为测试数据。
2.边界值分析设计测试用例
这里讨论一个有两个变量x1和x2的程序P。假设输入变量x1和x2在下列范围内取值:
a≤x1≤b,c≤x2≤d边界值分析利用输入变量的最小值(min),稍大于最小值(min+),域内任意值(nom),稍小于最大值(max一),最大值(max)

来设计测试用例。即通过使所有变量取正常值,只使一个变量分别取最小值、略高于最小值、略低于最大值和最大值。对于一个n变量的程序,

边界值分析测试会产生4n+1个测试用例。
3.健壮性边界值测试
健壮性测试是边界值分析的一种扩展。变量除了取min,min+,nom,max一,max5个边界值外,还要考虑采用一个略超过最大值(max+)以及一个

略小于最小值(min一)的取值,看看超过极限值时系统会出现什么情况。
健壮性边界值测试将产生(6n+1)个测试用例。
健壮性测试最有意义的部分不是输入,而是预期的输出,观察例外情况如何处理。
4.内部边界值
在多数情况下,边界值条件是基于应用程序的功能设计而需要考虑的因素,可以从软件的规格说明或常识中得到,也是最终用户可以很容易发

现问题的。然而,在测试用例设计过程中,某些边界值条件是不需要呈现给用户的,或者说用户是很难注意到的,但同时确实属于检验范畴内

的边界条件,称为内部边界值条件或子边界值条件。
内部边界值条件主要有下面几种:
(1)数值的边界值检验:计算机是基于二进制进行工作的,因此,软件的任何数值运算都有一定的范围限制,具体见表3—6。
(2)字符的边界值检验:在计算机软件中,字符也是很重要的表示元素,其中ASCII和Unicode是常见的编码方式。表3—7列出了一些常用字符对

应的ASCII码值。

3.2.3正交分析法
1.基本概念正交分析法是研究与处理多因素试验的一种科学方法,它在实际经验与理论分析的基础上,科学地挑选出代表性强的少数试验,找

到最好或较优的方案。简单地说,就是用正交表安排试验方案以及试验结果。
在正交分析法中,通常把判断试验结果优劣的标准叫做试验的指标,把有可能影响试验指标的条件称为因子(或因素),而影响试验因子的称为

因子的水平(或状态)。
正交表是一种具有“整齐可比性”和“均衡搭配性”的二维数字表格。“均衡搭配性”使试验点均衡地分布在试验范围内,让每个试验点有充

分的代表性;“整齐可比性”使试验结果的分析十分方便,可以估计各个因素对指标的影响,找出影响事物变化的主要因素。
2.正交分析法设计测试用例的步骤
(1)提取功能说明。构造因子一状态表。利用正交分析法来设计测试用例时,首先要根据被测试软件的规格说明书找出影响其功能实现的操作对

象和外部因素,把它们当作因子,而把各个因子的取值当作水平(或状态)。对软件需求规格说明中的功能要求进行划分,把整体的、概要性的

功能要求进行层层分解与展开,分解成具体的有相对独立性的、基本的功能要求。这样就可以把被测试软件中所有的因子都确定下来。并为确

定每个因子的权值提供参考的依据。确定因子与状态是设计测试用例的关键,因此要求尽可能全面地、正确地确定取值,以确保测试用例的设

计完整、有效。
(2)加权筛选,生成因素分析表。对因子与状态的选择可按其重要程度分别加权。可根据各个因子及状态的作用大小、出现频率的大小以及测试

的需要,确定权值的大小。必要时,可以删除一部分权值较小,或者说重要性较小的因子或水平,使最后生成的测试用例的数目控制在允许的

范围之内。
(3)利用正交表构造测试数据集(正交表中所描述的组合可直接转化为测试用例,再增加一些没有生成的但可疑的测试用例)。

3.2.4决策表在所有功能性测试方法中,决策表具有严格逻辑性,被认为是最严格的测试方法。决策表能把复杂的逻辑关系和多种条件组合的

情况表达得比较明确。决策表由4部分组成,见表3—18。

3.3结构性测试

结构性测试又称白盒测试、逻辑驱动测试或基于程序的测试,是根据被测程序的内部结构设计测试用例的一类测试。它依赖于对程序细节的严

密检验,针对特定条件和循环集设计测试用例,对软件的逻辑路径进行测试。在程序的不同点检验“程序的状态”以判定其实际情况是否和预

期的状态相一致。
因此,白盒测试要求对某些程序的结构特性做到一定程度的覆盖,或者说是“基于覆盖的测试”,并以此为目标,引导测试人员朝着提高覆盖

率的方向努力,找出那些被忽视的程序错误。
逻辑覆盖主要是依据被测程序的逻辑结构设计测试用例,驱动被测程序运行完成测试。从覆盖源程序语句的详尽程度分析,有不同的覆盖标准



3.3.1语句覆盖
语句覆盖就是设计若干个测试用例,运行被测试程序,使得每一条可执行语句至少执行一次。
为了说明简略,分别对各个判断的取真、取假分支编号为b,c,d,e。
为了测试语句覆盖率,只要设计一个测试用例就可以把3个执行语句块中的语句覆盖了。
测试用例输入为:{x一4,y一5,z一5)
程序执行的路径是:abd
该测试用例虽然覆盖了可执行语句,但并不能检查判断逻辑是否有问题,例如在第一个判断中把&8L错误地写成了lI,则上面的测试用例仍可

以覆盖所有的执行语句。可以说语句覆盖是最弱的逻辑覆盖准则。

3.3.2分支覆盖
分支覆盖就是设计若干个测试用例,运行所测程序,使程序中每个判断的取真分支和取假分支至少执行一次。

3.3.3条件覆盖

条件覆盖就是设计若干个测试用例,运行被测试对象,使得程序中每个判断的每个条件的可能取值至少执行一次。

对例子中的所有条件取值加以标记。例如:

对于第一个判断:

条件x>3,取真值为T1,取假值为一T1;

条件z<10,取真值为T2,取假值为一T2。

对于第二个判断:

条件x一4,取真值为T3,取假值为一T3;

条件y>5,取真值为T4,取假值为一T4。

则可以设计测试用例如表3—21所示。

上面的测试用例不但覆盖了所有分支的真、假两个分支,而且覆盖了判断中的所有条件的可能值。

3.3.4分支条件覆盖分支条件覆盖就是设计足够的测试用例,使得判断中每个条件的所有可能取值至少执行一次,同时每个判断的所有可

能判断结果至少执行一次,即要求各个判断的所有可能的条件取值组合至少执行一次。
根据定义只需设计如表3—22所示的两个测试用例便可以覆盖8个条件值以及4个判断分支。
分支条件覆盖从表面来看。它测试了所有条件的取值,但是实际上某些条件掩盖了另一些条件。例如对于条件表达式(x>3)&&(z<10)来说,必须两个条件都满足才能确定表达式为真。如果x>3为假则一般的编译器不再判断是否z<10了。对于第二个表达式(x一=4)II(y>5)来说,若x一一4,测试结果为真,就认为表达式的结果为真,这时不再检查y>5了。因此,采用分支条件覆盖,逻辑表达式中的错误不一定能够查出来了。

3.3.5条件组合覆盖
条件组合覆盖就是设计足够的测试用例,运行被测试对象,使得每一个判断的所有可能的

条件取值组合至少执行一次。

现在对例子中的各个判断的条件取值组合加以标记如下:

x>3,z<10记做T1T2.第一个判断的取真分支

x>3,z>一10记做T1一T2,第一个判断的取假分支

x<一3,z<10记做一T1T2,第一个判断的取假分支

x<一3,z>一10记做一T1一T2,第一个判断的取假分支

x=4,y>5记做T3T4,第二个判断的取真分支

x一4,y<一5记做T3一T4,第二个判断的取真分支

x!一4,y>5记做一T3T4,第二个判断的取真分支

x!一4,y<一5记做一T3一T4,第二个判断的取假分支

根据定义取4个测试用例,就可以覆盖上面8种条件取值的组合。

上面的测试用例覆盖了所有条件的可能取值的组合,覆盖了所有判断的可取分支,但是却丢失了一条路径abe。

3.3.6路径覆盖

路径覆盖就是选取足够多的测试用例。覆盖被测试对象中的所有可能路径。

在表3—23所示的条件组合覆盖测试用例中再添加一个测试用例就可对程序进行全部的路径覆盖,见表3—24。

3.3.7基本路径测试

前面的例子程序是一个很简单的函数程序,只有4条路径。但在实践中,一个不太复杂的程序,其路径都是一个庞大的数字,要在测试中覆盖所有的路径是不现实的。为了解决这一难题,只得把覆盖的路径数压缩到一定限度内,例如,程序中的循环体只执行一次,基本路径测试就是这样一种测试方法,它在程序控制图的基础上,通过分析控制构造的环行复杂性,导出基本可执行路径集合,从而设计测试用例。设计出的测试用例要保证在测试中程序的每一个可执行语句至少执行一次。具体过程可分为4个步骤。

(1)画程序的控制流图:描述程序控制流的一种图示方法。

(2)计算程序圈复杂度(McCabe)。从程序的环路复杂性可导出程序基本路径集合中的独立路径条数。这是确定程序中每个可执行语句至少执行一次所必需的测试用例数目的上界。

(3)导出测试用例:根据圈复杂度和程序结构设计用例数据输入和预期结果。

(4)准备测试用例:确保基本路径集中的每一条路径的执行。

在给出具体例子之前,先介绍一下圈复杂度及其计算:

圈复杂度是一种代码复杂度的衡量标准,在软件测试中,用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,即合理的预防错误所需测试的最少路径条数。圈复杂度大说明程序代码可能质量低且难以测试和维护,根据经验,程序的可能错误和高的圈复杂度有着很大关系。

下面就用一个简单的例子来介绍一下圈复杂度V(G)的3种计算方法。

(1)画出控制流图。
C/C+4-语句中的控制语句表示含义如下:
图中的每一个圆称为流图的节点,代表一条或多条语句。流图中的箭头称为边或连接,代表控制流。
为了说明流图的用法,采用过程设计表示法,此处,流程图用来描述程序控制结构。可将流程图映射到一个相应的流图(假设流程图的菱形判断框中不包含复合条件)。在流图中,每一个圆。称为流图的节点,代表一个或多个语句。一个处理方框序列和一个菱形判断框可被映射为一个节点.流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个节点,即使该节点并不代表任何语句。由边和节点限定的范围称为区域。计算区域时应包括图外部的范围。
任何过程设计都要被翻译成控制流图。
以上程序流程图和对应的控制流图分别如图3.6和图3.7所示。
程序设计中遇到复合条件时,生成的流图变得更为复杂。当条件语句中用到一个或多个布尔运算符(or,and,nand,nor)时,就出现了复合条件。如图3.8所示为语句ifaorb中的每一个a和b创建了一个独立的节点,包含条件的节点被称为判定节点,从每一个判定节点发出两条或多条边。
圈复杂度是一种为程序逻辑复杂性提供定量测度的软件度量,将该度量用于计算程序的基本的独立路径数目,为确保所有语句至少执行一次的测试数量的上界。独立路径必须包含一条在定义之前不曾用到的边。

3.3.8循环结构测试
代码覆盖中没有说明如何测试循环体。在程序中,循环体可分为两类:循环次数固定的循环体和循环次数不固定的循环体。

对于循环次数固定的循环,设循环次数为m,由于中途不会退出循环,因而只需要考虑两种情况:一是循环m次的情况,二是跳过循环不执行的情况。

下面讨论循环执行的执行次数不固定循环体的测试方法。这一类循环过程中可能中途退出循环,每次执行循环的次数可能不一样。设循环最大次数n>3,循环执行次数不固定,则循环测试应考虑以下情况:

(1)跳过这个循环;
(2)只循环1次;
(3)循环2次;
(4)循环m次,2 (5)循环n一1次;
(6)循环n次。

在测试一个循环的时候,应选择一组数据组合,把上述6种情况遍历。对于嵌套循环,其测试方法如下:

(1)使用上述单层循环的测试方法,对最内层循环进行测试;

(2)由内向外构造上述测试用例;

(3)重复步骤(2)直至测试完所有循环。
对于嵌套循环的测试,需要注意以下两种情况:
(1)相互平行的循环。即由条件判断,确定程序进入相互平行的循环体中的某一个。该情况参照条件组合覆盖。
(2)前后相接的循环。一个循环结束之后接着另一个循环。如果两个循环之间没有关联,则采取单层循环的测试方法;否则,采取嵌套循环的测试方法,即把后面的循环看作嵌入到前面的循环中的循环进行测试。

3.3.9程序插桩测试程序插桩是一种通过向被测程序中插人操作来发现和定位错误的方法,在程序调试中有着广泛的应用。
在测试和调试程序时,往往要在程序中插入一些打印语句(有的时候是以日志文件的形式存在的),以便在程序执行过程中,打印出需要的信息,通过这些信息来了解程序执行过程中的动态特性。例如程序的实际执行路径,程序中某语句的执行次数,程序中某变量在特定时刻的值,等等,都可以通过程序插桩来完成。
设计程序插桩要考虑以下3个问题:

(1)需要知道程序的哪些信息;
(2)在什么位置设置测试点;
(3)打印日志的延迟是否会改变程序的运行方式。

问题(1)要根据具体的系统进行分析。问题(2),通常在一个顺序执行的结构中只插入一条语句,以减少测试点,尽量减少对程序执行的影响。问题3,在时间关键或者一些和时间相关操作的程序中更要加以关注。

同时采用程序插桩要注意以下3点:
(1)要保证插桩语句自身的正确性;
(2)插桩后的程序,严格意义上已经异于原来的程序,相关特性要重新评估;
(3)调试和测试之后要去除插桩语句(工程上普遍采用条件宏定义的方法)。
具体项目中常常会用匈牙利命名法,来表示具体测试函数的具体测试项目。

3.4静态分析
静态分析的主要特征是在用计算机测试源程序时,计算机并不真正运行被测试的程序,只是进行特征分析。因此,静态分析是对被测试程序进行特征分析的一些方法的总称。这里主要介绍静态测试中常用的控制流分析、数据流分析和代码检查3种分析形式。

3.4.1控制流分析
一个程序的控制流关系叙述了程序元素和它们的执行次序之间的联系。一个程序元素通常是一个条件、一个简单的语句,或是一块语句(多个连续语句)。如果元素B可以在元素A之后立即执行,那么(A,B)就在程序的控制流关系中,后继的B的执行独立于A的执行。例如。若A指的是条件(x 尽管事实上A总为假,但(A,B)还是在控制关系流中存在着。
对应于控制流关系的图被称为控制流图。图上的每个节点对应于一个程序元素;两个节点间一个直接的弧,表示相应的两个元素在控制流关系中组成一个顺序对。控制流图的一条路径对应于一个潜在可执行的程序元素顺序。执行一条路径就是执行对应的程序元素序列。如果一个输入引起一条路径的执行,那么这条路径就被称之为是可达的,否则是不可达的。通常,含循环的路径有无限多条,即使没有循环,一个程序也可能有非常多的路径需要分析。

3.4.2数据流分析
程序和程序的元素通过它们的数据访问行为关联起来,这就确定了数据流关系。如果元素B使用一个数据对象,该数据对象潜在地在元素A处被定义,那么(A,B)就出现在程序的数据流关系中。数据流图是一个直接被标记的图形。它对应于数据流关系,其中节点对应于程序元素,直接连接A到B的弧用v标记。这里的v表示(A,B)在数据流关系中是由于在A处定义了v,在B处使用了v。

一个程序可以表示成一个数据流图,使用变量定义、引用和未定义信息做标记。如果一个语句的执行分配了一个值给一个变量,则称这个变量被定义了。一个变量的引用是指,一个语句的执行需要从内存中获得某个变量的值。观察下面的语句:

其中。Y和Z都是被引用,而X先被引用,然后又被定义。一个变量在许多情况下可能会变成未定义。例如,在FORTRAN程序中,一个DO语句的指示变量在循环结束时就变成未定义的,局部变量在子程序用RETURN返回后变成未定义的。

关于数据流的分析可以被引用到代码优化、异常检测和测试数据生成中。

3.4.3接口分析
接口分析,也叫接口一致性分析,主要用于程序静态分析和设计分析。接口一致性分析设计模块之间的接口的一致性以及模块与外部数据之间的一致性。

接口一致性分析还设计子程序以及函数之间接口的一致性,包括检查形参与实参的类型、个数、维数、顺序的一致性。当子程序之间的数据或者控制传递使用公共变量或全局变量时。也应检查它们的一致性。

3.4.4表达式分析

对表达式进行分析,可以发现和纠正表达式出现的问题。其中主要包括以下问题:

(1)除数为零;

(2)开方数值为负;

(3)浮点数的比较,直接使用“<”“>”或者“一”;

(4)算数溢出;

(5)数组越界;

(6)数组引用错误。

其中问题(3)需要特别注意,由于计算机所使用的二进制计数法,不能精确地表示十进制浮点数,因而常使得计算结果出人意料。

3.4.5代码检查
代码检查是一种非常有效的程序验证技术,对于典型的程序来说,可以查出30%~70%的逻辑设计错误和编码错误。

正式的审查是一个由审查小组实施的团队活动,审查小组至少包括以下4个成员:

开发者。被审查代码的开发者是一个重要角色。

审查负责人。审查负责人是小组中发现错误、冗余和不一致性的主要人物。

阅读者。阅读者是一个负有重要责任的成员,主要为整个小组阅读代码。

协调者。协调者的任务是组织会议、对发现的错误进行记录。

评审的所有参与者都是审查员,但是产品开发者不能充当负责人、阅读者或记录人。如果某个人是审查小组中的任何人的上级管理者,那么就不应该参与审查。当审查负责人要求时,软件产品相关负责人应该提供所需的额外资料。
审查的最终目标是尽量在其根源处发现和修正错误,以降低返工的成本。软件审查需要人为地检查源代码和文档表示,以发现其中的异常和缺陷,旨在发现缺陷而不是改正。在审查过程中需要执行的活动包括:

(1)为审查小组成员提供准确的系统概述。
(2)设计并描述出阅读者对被查产品进行阐述的方式。
(3)事先把源代码和相关文档分发给审查小组成员。
(4)在审查过程中发现错误进行准确记录,以供日后查阅。
(5)在审查过程中提问,并对问题进行追踪直到发现错误。
(6)对发现的错误进行评审,以便揭露和修复错误。
(7)根据结果决定是否需要再次审查。
代码检查比计算机测试优越的是:一次审查中可能发现许多不同的缺陷。而计算机测试发现错误之后,通常需要先改正这个错误才能继续测试,因此错误是一个一个地发现并改正的。也就是说,采用代码检查的方法可以减少系统验证的总工作量。

3.5动态分析
3.5.1内存处理和内存泄漏
对于程序中某一进程或程序的内存占用情况,以及占用比例,或是内存分配中存在的错误,或是由于疏忽或错误造成程序未能释放已经不再使用的内存的内存泄漏情况,应设计测试用例来证明这些存储或使用目标没有得到满足。

内存错误:当一个指针或者该指针所指向的内存单元成为无效单元,或者内存中分配的数据结构被破坏时,就会造成内存错误。

程序使用的内存和辅存的容量,以及临时文件或溢出文件的大小,应设计测试用例来证明这些存储目标没有得到满足。

内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

3.5.2常见运行错误
运行错误指的是那些在运行时出现的错误,如除数等于零、指针地址无效等问题。运行错误在语法检查时一般无法发现,但一旦发生很可能导致系统崩溃。下面用几个例子来介绍一下一些常见的运行错误。

为了说明这个例子,首先分析一个简单的隐式整型表达式c=a+b(假设a的存储位数不大于b的存储位数),编译器是这样来处理这个表达式的:如果b是短整型(即位数少于int,比如char,short等)或者整型(int或unsignedint),那a也是短整型或者整型,执行“+”运算之前,a和b都将被扩充为整型(int或者unsignedint),然后相加的结果赋给c(如果c不是int或者unsignedint类型,则这个赋值操作也会包含隐式的扩充或截断操作)。如果b是长整型(存储位数多于int),则a会被扩充为与b相当的长整型,再执行“+”运算,所得结果赋给c(可能包含隐式的扩充或截断操作)。绝大部分的操作符用于整型运算的时候,都遵循上述“平衡”原则,比如:算术操作符、位操作符和关系运算符。但逻辑操作符不遵循上述“平衡”原则。此外左移(<<)和右移(>>)运算符也不遵循“平衡”原则,只和移位操作符左边的整型操作数相关。假设一个8位的短整型变量值为Oxf5(十六进制),则右移4位所得结果是OxOf(十六进制)。

例3.2中的代码的原意是将port的值取反后右移4位赋值给result一8,程序员期望的结果显然是result一8一OxOa。然而,由于整型的“平衡”原则,在16位编译器中,~port的值是Oxffa5;在32位编译器中,port的值是Oxffffffa5。无论哪种情况,最后结果(右移4位后赋值给result一8的时候有一个截断操作)都是result_8=Ox:fa,而非程序员预期的result一8=OxOa。

倘若将最后一行代码改成result一--((uin8一t)("~port))>>4,则result一8可取得预期的值。当然,result_8=((~port)&OxOf也可以得到预期的值。如果位操作符~和移位操作符<<(或>>)联合作用于unsignedchar或者unsignedshort类型的操作数时,中间运算步骤的结果必须立刻显式强制转换为预期的短整型数据类型。

在c标准中,条件语句需要的是布尔值,条件语句表达式的布尔值实际上是按照整型处理的.所以上述两段代码在语法和逻辑上都没有任何问题。第一段代码判断x是否等于y,如果相等,调用foo()函数;第二段代码首先将y的值赋给x,然后判断x是否为o,如果不为o,调用foo()函数。这两段代码只相差一个等号,却使判断条件大不相同,程序的执行流程会出现很大差别。

相信读者在写程序的时候都碰到过将“一一”这个判断符误写成赋值符“一”的情况。那么面对这两个语句时,如何能快速准确地判断这是正确的还是程序员的失误呢?当程序比较简单的时候,很容易判断,但当程序流程比较复杂的时候,可能花费大量时间还难以给出确定的答案,而这些地方极有可能是有错误的。

3.5.3覆盖率分析
覆盖率是用来度量测试完整性的一个手段,通过覆盖率数据,可以知道测试得是否充分.测试的弱点在哪些方面,进而指导我们设计能够增加覆盖率的测试用例。这样就能够有效地提高测试质量。

现在有很多测试工具都能够支持覆盖率测试,但切忌盲目追求绝对100%的覆盖率。虽然如果有足够的资源和时间,达到100%的覆盖率是现实的,但事实上,为了达到100%的覆盖率将付出极大的成本,也是不必要的。对于一般的软件,应当设置一个合理的覆盖率标准。研究表明,80%的错误隐藏在20%的代码中,从成本效率考虑,应当把覆盖率和代码静态分析工具结合在一起使用,去覆盖那些容易出错的代码,而忽略那些简单的和不易出错的代码。

3.5.4性能分析
软件都有特定的性能或效率目标,这些特性描述为在特定负载和配置环境下程序的响应时间和吞吐率。因此.性能分析主要是设计测试用例来说明程序不能满足其性能目标.或是帮助找到应用程序的瓶颈所在。
具体分析项目如下:
(1)分析程序计算处理的精度;
(2)分析程序响应时间是否符合设计要求;
(3)分析程序所占用的空间是否符合要求;
(4)分析程序所能承受的最大负荷是否达标;
(5)分析程序是否合理地利用了硬件资源;
(6)分析程序的并发程度是否达到要求。

3.5.5安全性分析
安全性测试是检验软件中存在的安全性、数据保密性措施是否有效的测试。安全性测试应尽可能在符合实际使用条件下进行。着重对以下项目进行分析:
(1)对安全性关键部分,必须进行单独的安全性分析;
(2)分析软件防止出现危险状态措施的有效性和危险状态下的反应;
(3)对设计中关系到安全性的数据结构保护、算法、容错、冗余及中断处理方案等逐个进行有针对性的分析;
(4)分析软件系统对抗非法数据访问的能力。

文章来源: 秘奥软件网,中小企业信息化领跑者!全国咨询热线:400-9908-527_www.misall.com

最新新闻: 上一篇: 下一篇: