实现与测试

本文详述了软件开发的编码与测试过程,强调了选择合适编程语言、遵循编码风格的重要性,以及软件测试的基础原则。文章介绍了单元测试、集成测试、确认测试和回归测试的不同策略,探讨了白盒测试和黑盒测试技术,如逻辑覆盖、边界值分析等。此外,还涵盖了调试方法和软件可靠性的评估,强调了测试在保证软件质量中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编码就是把软件设计结果翻译成用某种程序设计语言书写的程序,是对设计的进一步具体化

程序的质量主要取决于软件设计的质量。软件测试是保证软件质量的关键步骤,是对软件规格说明、设计和编码的最后复审

编码 

选择程序设计语言

程序设计语言是人和计算机通信的最基本的工具,会影响人的思维和解题方式,影响人和计算机通信的方式和质量,影响其他人阅读和理解程序的难易程度。

选择适宜的程序设计语言的原因:

  • 根据设计去完成编码时,困难最少;
  • 可以减少需要的程序测试量;
  • 可以得到更容易阅读和更容易维护的程序(极端重要)

高级语言优于汇编语言:

  • 汇编语言编码需要把软件设计翻译成机器操作的序列, 既困难又容易出差错;
  • 高级语言写程序比用汇编语言写程序生产率可以提高好几倍;
  • 用高级语言写的程序容易阅读、容易测试、容易调试、 容易维护。

理想标准:

  • 应该有理想的模块化机制,以及可读性好的控制结构和数据结构;
  • 使编译程序能够尽可能多地发现程序中的错误;
  • 应该有良好的独立编译机制。

实用标准:

  • 系统用户的要求;
  • 可以使用的编译程序;
  • 可以得到的软件工具;
  • 工程规模;
  • 程序员的知识;
  • 软件可移植性要求;
  • 软件的应用领域

编码风格(逻辑清晰、易读易懂)

源程序代码的逻辑简明清晰、易读易懂是好程序的一个重要标准,为了做到这一点,应该遵循下述规则。  

1.程序内部的文档
所谓程序内部的文档包括恰当的标识符、适当的注解和程序的视觉组织等。

  • 标识符:含义鲜明的名字、缩写规则一致、为名字加注解;
  • 注解:正确性,简要描述模块的功能、主要算法、接口特点、 重要数据以及开发简史或解释包含这段代码的必要性;
  • 视觉组织:适当的阶梯形式使程序的层次结构清晰明显。

2.数据说明     
数据说明的原则:

  • 数据说明的次序应该标准化;
  • 当多个变量名在一个语句中说明时,应该按字母顺序排列这些变量/行业内的约定标准
  • 如果设计时使用了一个复杂的数据结构(能不用就不用),则应该用注解说明用程序设计语言实现这个数据结构的方法和特点。


3.语句构造
下述语句构造的原则有助于使语句简单明了:

  • 不要为了节省空间而把多个语句写在同一行;
  • 尽量避免复杂的条件测试,不主张多个逻辑条件复用
  • 尽量减少对“非”条件的测试(数据库中);
  • 避免大量使用循环嵌套和条件嵌套;
  • 利用括号使逻辑表达式或算术表达式的运算次序清晰直观(避免程序难读)

4.输入输出 
在设计和编写程序时需考虑有关输入输出风格的规则:

  • 对所有输入数据都进行检验; (如:某省某市谋县)
  • 检查输入项重要组合的合法性;
  • 保持输入格式简单;
  • 使用数据结束标记,不要要求用户指定数据的数目;
  • 明确提示交互式输入的请求,详细说明可用的选择或边界数值;
  • 程序设计语言对格式有严格要求时,应保持输入格式一致;
  • 设计良好的输出报表;
  • 给所有输出数据加标志

5.效率   效率主要指处理机时间和存储器容量两个方面。

  • 效率是性能要求,因此应该在需求分析阶段确定效率方面的要求;
  • 效率是靠好设计来提高的;
  • 程序的效率和程序的简单程度是一致的,不要牺牲程序的清晰性和可读性来不必要地提高效率(不要炫技)。

 (1) 程序运行时间    
写程序的风格会对程序的执行速度和存储器要求产生影响,应遵循的规则如下:

  • 写程序之前先简化算术的和逻辑的表达式;
  • 仔细研究嵌套的循环,以确定是否有语句可以从内层往外移;
  • 尽量避免使用多维数组;
  • 尽量避免使用指针和复杂的表;
  • 使用执行时间短的算术运算;(有意识研究风格,优化
  • 不要混合使用不同的数据类型;
  • 尽量使用整数运算和布尔表达式

(2) 存储器效率

  • 在大型计算机中必须考虑操作系统页式调度的特点,一般说来,使用能保持功能域的结构化控制结构,是提高效率的好方法。
  • 在微处理机中如果要求使用最少的存储单元,则应选用有紧缩存储器特性的编译程序,在非常必要时可以使用汇编语言。
  • 提高执行效率的技术通常也能提高存储器效率。提高存储器效率的关键同样是“简单”。

(3) 输入输出的效率     
简单清晰是提高人机通信效率的关键。从写程序的角度看,却有些简单的原则可以提高输入输出的效率。

  • 所有输入输出都应该有缓冲,以减少用于通信的额外开销;
  • 对二级存储器(如磁盘)应选用最简单的访问方法
  • 二级存储器的输入输出应该以信息组为单位进行;
  • 如果“超高效的”输入输出很难被人理解,则不应采用这种方法。 

软件测试基础  

软件测试的目标

关于测试的一些规则如下:

  • 测试是为了发现程序中的错误而执行程序的过程。
  • 好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案。
  • 成功的测试是发现了至今为止尚未发现的错误的测试。

测试的正确定义是“为了发现程序中的错误而执行程序的过程”。
测试决不能证明程序是正确的。即使经过了最严格的测试之后, 仍然可能还有没被发现的错误潜藏在程序中。
另外,在综合测试阶段通常由其他人员组成测试小组来完成测试工作(心理学角度)。

软件测试准则

  • 所有测试都应该能追溯到用户需求;
  • 应该远(需求分析)在测试开始之前就制定出测试计划;
  • 应该从“小规模”测试开始,并逐步进行“大规模”测试;
  • 穷举测试是不可能的;(时间、人力、其他资源)
  • 为了达到最佳的测试效果,应该由独立的第三方从事测试工作(承担模块测试工作)

测试方法

黑盒测试(又称功能测试—>接口)把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。
黑盒测试是在程序接口进行的测试, 检查:
程序功能是否能按照规格说明书的规定正常使用;
程序是否能适当地接收输入数据并产生正确的输出信息;
程序运行过程中能否保持外部信息(例如数据库或文件)的完整性。

白盒测试(又称结构测试) 是把程序看成装在一个透明的白盒子里,测试者完全知道程序结构和处理算法。
这种方法按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求(详细设计)正确工作。

测试步骤

测试过程也必须分步骤进行,后一个步骤在逻辑上是前一个步骤的继续。

大型软件系统通常由若干个子系统组成,每个子系统又由许多模块组成,因此,大型软件系统的测试过程基本上由模块测试、子系统测试、系统测试、验收测试和平行运行等五个步骤组成。

1.模块测试(单元测试)
在设计得好的软件系统中,每个模块完成一个清晰定义的子功能,而且这个子功能和同级其他模块的功能之间没有相互依赖关系。因此,有可能把每个模块作为一个单独的实体来测试,而且通常比较容易设计检验模块正确性的测试方案。模块测试的目的是保证每个模块作为一个单元能正确运行, 所以模块测试通常又称为单元测试。模块测试所发现的往往是编码和详细设计的错误

2.子系统测试   
子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间的协调和通信是这个测试过程中的要解决的主 要问题,因此,这个步骤着重测试模块的接口

3.系统测试   
系统测试是把经过测试的子系统装配成一个完整的系统来测试。 在这个过程中不仅应该发现设计和编码的错误,还应该验证系统确实能提供需求说明书中指定的功能,而且系统的动态特性也符合预定要求。系统测试发现的往往是软件设计中的错误,也可能发现需求说明中的错误。      

子系统测试和系统测试,都兼有检测和组装两重含义,通常称为集成测试。

4.验收测试(确认测试)
验收测试把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但是它是在用户积极参与下进行的,而且可能主
要使用实际数据(系统将来要处理的信息)进行测试。验收测试的目的是验证系统确实能够满足用户的需要,验收测试发现的往往是系统需求说明书中的错误。

5.平行运行  
所谓平行运行就是同时运行新系统和将被它取代的旧系统,以便比较新旧两个系统的处理结果。   
这样做的具体目的有如下几点。  
(1)可以在准生产环境中运行新系统而又不冒风险。   
(2)用户能有一段熟悉新系统的时间。  
(3)可以验证用户指南和使用手册之类的文档(软件配置)。  
(4)能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标。

测试阶段的信息流

测试阶段的输入信息有两类:
    (1)软件配置,包括需求规格说明书、设计说明书和源程序清单等;
    (2)测试配置,包括测试计划和测试方案


测试方案不仅仅是测试时使用的输入数据(称为测试用例),还应该包括每组输入数据预定要检验的功能,以及每组输入数据预期应该得到的正确输出
测试配置是软件配置的一个子集,最终交出的软件配置应该包括上述测试配置以及测试的实际结果和调试的记录。
比较测试得出的实际结果和预期的结果,如果两者不一 致则很可能是程序中有错误。

  • 如果经常出现要求修改设计的严重错误,那么软件的质量和可靠性是值得怀疑的,应该进一步仔细测试。
  • 如果看起来软件功能完成得很正常,遇到的错误也很容易改正,则仍然应该考虑两种可能:(1)软件的可靠性是可以接受的;(2)所进行的测试尚不足以发现严重的错误。
  • 如果经过测试,一个错误也没有被发现,则很可能是因为对测试配置思考不充分,以致不能暴露软件中潜藏的错误。

 软件可靠性模型使用错误率数据估计将来出现错误的情况, 并进而对软件可靠性进行预测。

单元测试  

单元测试集中检测软件设计的最小单元——模块。
单元测试和编码属于软件过程的同一个阶段。
在源程序代码通过编译程序的语法检查后,可以用详细设计描述作指南,对重要的执行通路进行测试,以便发现模块内部的错误。
可以应用人工测试和计算机测试这样两种不同类型的测试方法,完成单元测试工作。

单元测试主要使用白盒测试技术,而且对多个模块的测试可以并行地进行

测试重点

在单元测试期间着重从以下5个方面对模块进行测试。
1.模块接口
  对模块接口进行测试时主要检查以下几个方面:

  • 参数的数目、次序、属性或单位系统与变元是否一致;
  • 是否修改了只作输入用的变元;
  • 全局变量的定义和用法在各个模块中是否一致

2.局部数据结构
对于模块来说,局部数据结构是常见的错误来源。应该仔细设计测试方案,以便发现局部数据说明、初始化(变量不要由系统自动赋值)、默认值等方面的错误。

3.重要的执行通路
由于通常不可能进行穷尽测试,因此,在单元测试期间选择最有代表性、最可能发现错误的执行通路进行测试是十分关键的。应该设计测试方案用来发现由于错误的计算、不正确的比较或不适当的控制流而造成的错误。

4.出错处理通路
好的设计应该能预见出现错误的条件,并且设置适当的处理错误的通路。不仅应该在程序中包含出错处理通路,而且应该认真测试这种通路。评价出错处理通路应该着重测试下述一些可能发生的错误。
(1)对错误的描述是难以理解的;
(2)记下的错误与实际遇到的错误不同;
(3)在对错误进行处理之前,错误条件已经引起系统干预;
(4)对错误的处理不正确;
(5)描述错误的信息不足以帮助确定造成错误的位置

5.边界条件

  • 边界测试是单元测试中最后的也可能是最重要的任务
  • 软件常常在它的边界上失效,例如,处理n元数组的第n 个元素时,或做到i次循环中的第i次重复时,往往会发生错误。
  • 使用刚好小于、刚好等于和刚好大于最大值或最小值的数据结构、控制量和数据值的测试方案,非常可能发现软件中的错误。

代码审查

代码检查是指由审查小组正式对源程序进行人工测试。 它是一种非常有效的程序验证技术,对于典型的程序来说, 可以查出30%~70%的逻辑设计错误和编码错误。审查小组最好由下述4人组成。 (1) 组长,应该是一个很有能力的程序员,而且没有直接参与这项工程; (2) 程序的设计者; (3) 程序的编写者; (4) 程序的测试者。

       在审查会上由程序的编写者解释他是怎样用程序代码实现设计的,通常是逐个语句地讲述程序的逻辑,小组其他成员仔细倾听他 的讲解,并力图发现其中的错误。
       审查会上需要对照程序设计常见错误清单,分析审查这个程序。 当发现错误时由组长记录下来,审查会继续进行(审查小组的任务是发现错误而不是改正错误)。
       审查会另外一种常见的进行方法,称为预排:由一个人扮演 “测试者”,其他人扮演“计算机”。会前测试者准备好测试方案, 会上由扮演计算机的成员模拟计算机执行被测试的程序。
       测试方案在代码审查中起一种促进思考引起讨论的作用。在大多数情况下,通过向程序员提出关于他的程序的逻辑和他编写程序时所做的假设的疑问,可以发现的错误比由测试方案直接发现的错误还多。
       代码审查比计算机测试优越的是:一次审查会上可以发现许多错误;用计算机测试的方法发现错误之后,通常需要先改正这个错误才能继续测试,即:采用代码审查的方法可以减少系统验证的总工作量
       人工测试和计算机测试是互相补充,相辅相成的,缺少其中任何一种方法都会使查找错误的效率降低。

计算机测试

模块不是一个独立的程序,因此必须为每个单元测试开发驱动软件和(或)存根软件(也称虚拟子程序)——代表开销,为了进行单元测试必须编写测试软件,但并不把他们当作软件产品的一部分交给用户
       驱动程序是一个“主程序”,它接收测试数据,把这些数据传送给被测试的模块,并且印出有关的结果。
存根程序代替被测试的模块所调用的模块,它使用被它代替的模块的接口,可能做最少量的数据操作,印出对入口的检验或操作结果,并且把控制归还给调用它的模块。


集成测试  

集成测试是测试和组装软件的系统化技术。 由模块组装成程序时有两种方法。
一种方法是先分别测试每个模块(先完成所有单元测试), 再把所有模块按设计要求放在一起结合成所要的程序(再做集成测试),这种方法称为非渐增式测试方法

另一种方法是把下一个要测试的模块同跟已经测试好的那些模块结合起来进行测试,测试完以后再把下一个应该测试的模块结合进来测试。这种每次增加一个模块的方法称为渐增式测试, 这种方法实际上同时完成单元测试和集成测试

两种集成测试方法的比较:
非渐增式测试把所有模块放在一起,作为一个整体来测试。 测试时会遇到许多的错误,改正错误非常困难,因为在庞大的程序 中想要诊断定位一个错误非常困难,而且改正一个错误之后,马上又会遇到新的错误,这个过程会继续下去,没有尽头。
渐增式测试与“一步到位”的非渐增式测试相反,它把程序划分成小段来构造和测试,在这个过程中比较容易定位和改正错误 ;对接口可以进行更彻底的测试;可以使用系统化的测试方法。因此,目前在进行集成测试时普遍采用渐增式测试方法
当使用渐增方式把模块结合到程序中去时,有自顶向下和自底向上两种集成策略。

自顶向下集成

       自顶向下集成方法是从主控制模块开始,沿着程序的控制层次向下移动,逐渐把各个模块结合起来。再把附属于(及最终附属于)主控制模块的那些模块组装到程序结构中去。   
自顶向下集成方法有两种策略:深度优先策略和宽度优先策略。
深度优先的结合方法逐步组装软件结构的一条通路上(垂直方向)的所有模块。选择一条通路取决于应用的特点,并且有很大任意性。
宽度优先的结合方法是沿软件结构水平地移动,把处于同一个控制层次上的所有模块组装起来。

自底向上集成

       自底向上测试从“原子”模块(即在软件结构最低层的模块)开始组装 和测试。因为是从底部向上结合模块,总能得到所需的下层模块处 理功能,所以不需要存根程序。
       用下述步骤可以实现自底向上的结合策略。
① 把低层模块组合成实现某个特定的软件子功能的族;
② 写一个驱动程序,协调测试数据的输入和输出;
③ 对由模块组成的子功能族进行测试;
④ 去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来形成更大的子功能族。   
上述第②~④步实质上构成了一个循环。

不同集成测试策略的比较

  • 自顶向下测试方法的主要优点是不需要测试驱动程序,能够在测试阶段的早期实现并验证系统的主要功能,而且能在早期发现上层模块的接口错误。
  • 自顶向下测试方法的主要缺点是需要存根程序,可能遇到与此相联系的测试困难,低层关键模块中的错误发现较晚,而且用这种方法在早期不能充分展开人力。
  • 自底向上测试方法的优缺点与上述自顶向下测试方法的优缺点刚好相反。

一般说来,纯粹自顶向下或纯粹自底向上的策略可能都不实用,人们在实践中创造出许多混合策略。 
(1) 改进的自顶向下测试方法。基本上使用自顶向下的测试方 法,但是在早期使用自底向上的方法测试软件中的少数关键模块 。一般的自顶向下方法所具有的优点在这种方法中也都有,而且能在测试的早期发现关键模块中的错误;但是,它的缺点也比自 顶向下方法多一条,即测试关键模块时需要驱动程序。
(2) 混合法。对软件结构中较上层使用的自顶向下方法与对软件结构中较下层使用的自底向上方法相结合。这种方法兼有两种方法的优点和缺点,当被测试的软件中关键模块比较多时,这种混合法可能是最好的折衷方法。

回归测试

  • 在集成测试过程中,每当一个新模块结合进来时,程序就发生了变化:建立了新的数据流路径,可能出现了新的I/O操作,激活了新的控制逻辑。
  • 回归测试是指重新执行已经做过的测试的某个子集,以保证上述这些变化(新模块结合进来)没有带来非预期的副作用
  • 回归测试就是用于保证由于调试或其他原因引起的变化,不会导致非预期的软件行为或额外错误的测试活动。
  • 回归测试可以通过人工地进行,也可以使用自动化的捕获回放工具自动进行。利用捕获回放工具,软件工程师能够捕获测试用例和实际运行结果,然后可以回放(即重新执行测试用例),并且比较软件变化前后所得到的运行结果。

回归测试集(已执行过的测试用例的子集)包括下述3类不同的测试用例。
(1) 检测软件全部功能的代表性测试用例。   
(2) 专门针对可能受修改影响的软件功能的附加测试。   
(3) 针对被修改过的软件成分的测试。
在集成测试过程中,回归测试用例的数量可能变得非常大。 因此,应该把回归测试集设计成只包括可以检测程序每个主要功能中的一类或多类错误的那样一些测试用例

确认测试  

  • 确认测试也称为验收测试,它的目标是验证软件的有效性
  • 验证指的是保证软件正确地实现了某个特定要求的一系列活动;   确认指的是为了保证软件确实满足了用户需求而进行的一系列活动。
  • 软件有效性的一个简单定义是:如果软件的功能和性能如同用户所合理期待的那样,软件就是有效的。
  • 需求分析阶段产生的软件需求规格说明书,准确地描述了用户对软件的合理期望,因此是软件有效性的标准,也是进行确认测试的基础。

确认测试的范围

       确认测试必须有用户积极参与,或以用户为主进行。用户应该参与设计测试方案,使用用户界面输入测试数据并且分析评价测试的输出结果。 确认测试通常使用黑盒测试法。应该仔细设计测试计划和测试过程,测试计划包括要进行的测试种类及进度安排,测试过程规定了用来检测软件是否与需求一致的测试方案。 通过测试和调试要保证软件能满足所有功能要求,能达到每个 性能要求,文档资料是准确而完整的,此外,还应该保证软件能满足其他预定的要求(例如安全性、可移植性、兼容性和可维护性等)。 确认测试有下述两种可能的结果: (1) 功能和性能与用户要求一致,软件是可以接受的。 (2) 功能和性能与用户要求有差距。

软件配置复查

       软件配置复查是确认测试的一个重要内容。复查的目的是保证软件配置的所有成分都齐全,质量符合要求,文档与程序完全 一致,具有完成软件维护所必须的细节,而且已经编好目录
       除了按合同规定的内容和要求,由人工审查软件配置之外,在确认测试过程中还应该严格遵循用户指南及其他操作程序,以 便检验这些使用手册的完整性和正确性。必须仔细记录发现的遗漏或错误,并且适当地补充和改正。

Alpha和Beta测试

如果一个软件是为许多客户开发的(例如,向大众公开出售的盒装软件产品),那么绝大多数软件开发商都使用被称为Alpha 测试和Beta测试的过程,来发现那些看起来只有最终用户才能发现的错误。
Alpha测试由用户在开发者的场所进行,并且在开发者对用户的 “指导”下进行测试。开发者负责记录发现的错误和使用中遇 到的问题。
Alpha测试是在受控的环境中进行的。
Beta测试由软件的最终用户们在一个或多个客户场所进行。与 Alpha测试不同,开发者通常不在Beta测试的现场。
Beta测试是软件在开发者不能控制的环境中的“真实”应用

白盒测试技术

       通常把测试数据和预期的输出结果称为测试用例
       不同的测试数据发现程序错误的能力差别很大,为了提高测试效率降低测试成本,应该选用高效的测试数据。因为不可能进行穷尽的测试,所以选用少量“最有效的”测试数据,做到尽可能完备的测试就更重要了。
       设计测试方案的基本目标是,确定一组最可能发现某个错误或某类错误的测试数据。已经研究出许多设计测试数据的技术, 这些技术各有优缺点;同一种技术在不同的应用场合效果可能相差很大,因此,通常需要联合使用多种设计测试数据的技术

逻辑覆盖

       逻辑覆盖是对一系列测试过程的总称,这组测试过程逐渐进行越来越完整的通路测试。         
       逻辑覆盖包括:语句覆盖、判定覆盖、条件覆盖、判定/条件 覆盖、条件组合覆盖、点覆盖、边覆盖、路径覆盖……

1.语句覆盖   
语句覆盖的含义是,选择足够多的测试数据,使被测程序中每条语句至少执行一次
语句覆盖只关心判定表达式的值,而没有分别测试判定表达式中每个条件取不同值时的情况
语句覆盖是很弱的逻辑覆盖标准。

2.判定覆盖
判定覆盖又叫分支覆盖,它的含义是,不仅每个语句必须至少执行一次,而且每个判定的每种可能的结果(真/假) 都应该至少执行一次,也就是每个判定的每个分支都至少执行一次。
判定覆盖一定是语句覆盖

3.条件覆盖   
条件覆盖的含义是,不仅每条语句至少执行一次,而且使判定表达式中的每个条件都取到各种可能的结果

4.判定/条件覆盖
判定/条件覆盖是一种能同时满足判定覆盖和条件覆盖的逻辑覆盖,它的含义是,选取足够多的测试数据,使得判定表达式中的 每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果。

5.件组合覆盖      
条件组合覆盖是更强的逻辑覆盖标准,它要求选取足够多的测试数据,使得每个判定表达式中条件的各种可能组合都至少出现一次。

满足条件组合覆盖标准的测试数据,也一定满足判定覆盖、条件覆盖和判定/条件覆盖标准。因此,条件组合覆盖是前述几种覆盖标准中最强的。 但是,满足条件组合覆盖标准的测试数据并不一定能使程序中的每条路径都执行到

6.点覆盖
从对程序路径的覆盖程度分析,能够提出下述一些主要的逻辑覆盖标准。   
图论中点覆盖的定义如下:如果连通图G的子图G′是连通的, 而且包含G的所有结点,则称G′是G的点覆盖。为了满足点覆盖的测试标准,要求选取足够多测试数据,使得程序执行路径至少经过流图中每个点一次。   
点覆盖标准和语句覆盖标准是相同的。


7.边覆盖和路径覆盖
图论中边覆盖的定义是:如果连通图G的子图G″是连通的,而 且包含G的所有边,则称G″是G的边覆盖。为了满足边覆盖的测试 标准,要求选取足够多测试数据,使得程序执行路径至少经过流图中每条边一次。通常边覆盖和判定覆盖是一致的。    路径覆盖的含义是,选取足够多测试数据,使程序的每条可能路径都至少执行一次(如果程序图中有环,则要求每个环至少经过一次)。

具体测试数据不唯一,边界值较优

控制结构测试

1.基本路径测试

       基本路径测试是Tom McCabe提出的一种白盒测试技术。使用基本路径测试设计测试用例时,首先计算程序的环形复杂度,并用环形复杂度为指南定义执行路径的基本集合,从该基本集合导出的测试用例可以保证程序中的每条语句至少执行一次,而且每个条件在执行时都将分别取真、假两种值。
       使用基本路径测试技术设计测试用例的步骤如下。   
            ① 根据过程设计结果画出相应的流图。   
            ② 计算流图的环形复杂度。    环形复杂度定量度量程序的逻辑复杂性。
            ③ 确定线性独立路径的基本集合。  
            独立路径是指至少引入程序的一个新处理语句集合或一个新条件的路径,即独立路径至少包含一条在定义该路径之前不              曾用过的边。   
            程序的环形复杂度决定了程序中独立路径的数量,而且这个数是确保程序中所有语句至少被执行一次所需的测试用例的上界
             ④ 设计可强制执行每条独立路径的测试用例。       
应该选取测试数据使得在测试每条路径时都适当地设置好各个判定结点的条件

2.条件测试   

用条件测试技术设计出的测试用例,能够检查程序模块中包含的逻辑条件。一个简单条件是一个布尔变量或一个关系表达式,在布尔变量或关系表达式之前还可能有一个NOT(┐)算符

3.循环测试

循环测试是一种白盒测试技术,它专注于测试循环结构的有效性。在结构化的程序中通常只有3种循环,即简单循环、串接循环和嵌套循环。



1、简单循环   
应该使用下列测试集(测试用例集合)来测试简单循环, 其中n是允许通过循环的最大次数。

  • 跳过循环。
  • 只通过循环一次。
  • 通过循环两次。
  • 通过循环m次,其中2 < m < n-1。
  • 通过循环n-1,n,n+1次。

(2) 嵌套循环   
如果把简单循环的测试方法直接应用到嵌套循环,测试数就会随嵌套层数的增加按几何级数增长,B.Beizer提出了一种能减少测 试数的方法,跳过循环。

  • 从最内层循环开始测试,把所有其他循环都设置为最小值。
  • 对最内层循环使用简单循环测试方法,而使外层循环的迭代参数(例如,循环计数器)取最小值,并为越界值或非法值增加一些额外的测试。
  • 由内向外,对下一个循环进行测试,但保持所有其他外层循环为最小值,其他嵌套循环为“典型”值。
  • 继续进行下去,直到测试完所有循环。

(3) 串接循环
如果串接循环的各个循环都彼此独立,则可以使用前述的测试简单循环的方法来测试串接循环。
如果两个循环串接,而且第一个循环的循环计数器值是第二个循环的初始值,则这两个循环并不是独立的。当循环不独立时
,建议使用测试嵌套循环的方法来测试串接循环

黑盒测试技术 

黑盒测试着重测试软件功能。黑盒测试并不能取代白盒测试, 它是与白盒测试互补的测试方法,它很可能发现白盒测试不易发现的其他类型的错误。   
黑盒测试力图发现下述类型的错误:
(1) 功能不正确或遗漏了功能;
(2) 界面错误;
(3) 数据结构错误或外部数据库访问错误;
(4) 性能错误;

(5) 初始化和终止错误。

白盒测试在测试过程的早期阶段进行,而黑盒测试主要用于测试过程的后期。  
设计黑盒测试方案时,应该考虑下述问题。
(1)怎样测试功能的有效性?
(2)哪些类型的输入可构成好测试用例?
(3)系统是否对特定的输入值特别敏感?
(4)怎样划定数据类的边界?
(5)系统能够承受什么样的数据率和数据量?
(6)数据的特定组合将对系统运行产生什么影响?

应用黑盒测试技术,能设计出满足下述标准的测试用例集。   
(1)所设计出的测试用例能够减少为达到合理测试所需要设计的测试用例的总数。   
(2)所设计出的测试用例能够告诉人们,是否存在某些类型的错误,而不是仅仅指出与特定测试相关的错误是否存在

等价划分

       等价划分把程序的输入域划分成若干个数据类,据此导出测试用例。等价划分法力图设计出能发现若干类程序错误的测试用例,从而减少必须设计的测试用例的数目。
       如果把所有可能的输入数据(有效的和无效的)划分成若干个等价类,则可以合理地做出下述假定:每类中的一个典型值在测 试中的作用与这一类中所有其他值的作用相同。因此,可以从每个等价类中只取一组数据作为测试数据。这样选取的测试数据最 有代表性,最可能发现程序中的错误。
       使用等价划分法设计测试方案首先需要划分输入数据的等价类,为此需要研究程序的功能说明,从而确定输入数据的有效等 价类和无效等价类。
       划分等价类需要经验,下述的启发式规则可能有助于等价类划分:   
        (1) 如果规定了输入值的范围,则可划分出一个有效的等价类(输入值在此范围内),两个无效的等价类(输入值小于最小值或大于最大值)。
        (2) 如果规定了输入数据的个数,则类似地也可以划分出一个有效的等价类和两个无效的等价类。
        (3) 如果规定了输入数据的一组值,而且程序对不同输入值做不 同处理,则每个允许的输入值是一个有效的等价类,此外还有一个无效的等价类(任一个不允许的输入值)。
        (4) 如果规定了输入数据必须遵循的规则,则可以划分出一个 有效等价类(符合规则)和若干个无效等价类(从各种不同角度违反规则)。
        (5) 如果规定了输入数据为整型,则可以划分出正整数、零和负整数3个有效类。
        (6) 如果程序的处理对象是表格,则应该使用空表,以及含一项或多项的表。

       划分出等价类以后,根据等价类设计测试方案时主要使用下面两个步骤。
       (1)设计一个新的测试方案以尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步骤直到所有有效等价类都被覆盖为止。   
       (2)设计一个新的测试方案,使它覆盖一个而且只覆盖一个尚未被覆盖的无效等价类,重复这一步骤直到所有无效等价类都 被覆盖为止

边界值分析

       经验表明,处理边界情况时程序最容易发生错误。例如,许多程序错误出现在下标、数据结构和循环等等的边界附近。因此 ,设计使程序运行在边界情况附近的测试方案,暴露出程序错误的可能性更大一些。
       使用边界值分析方法设计测试方案首先应该确定边界情况, 通常输入等价类和输出等价类的边界。选取的测试数据应该刚好等于、刚刚小于和刚刚大于边界值。
       通常设计测试方案时总是联合使用等价划分和边界值分析两种技术

错误推测

       错误推测法在很大程度上靠直觉和经验进行。它的基本想法是列举出程序中可能有的错误和容易发生错误的特殊情况,并且根据它们选择测试方案。
       经验表明,在一段程序中已经发现的错误数目往往和尚未发现的错误数成正比。例如,在IBM OS/370操作系统中,用户发现的全部错误的47%只与该系统4%的模块有关。因此,在进一步测试时要着重测试那些已发现了较多错误的程序段
       等价划分法和边界值分析法都只孤立地考虑各个输入数据的测试功效,而没有考虑多个输入数据的组合效应,可能会遗漏了输入数据易于出错的组合情况
       选择输入组合的一个有效途径是利用判定表或判定树为工具,列出输入数据各种组合与程序应作的动作(及相应的输出结果)之间的对应关系,然后为判定表的每一列至少设计一个测试用例。
       选择输入组合的另一个有效途径是把计算机测试和人工检查代码结合起来

调试

调试过程

       调试(也称为纠错)作为成功测试的后果出现,即调试是在测试发现错误之后排除错误的过程。       
       软件错误的外部表现和它的内在原因之间可能并没有明显的联系。调试就是把症状和原因联系起来的尚未被人深入认识的智力过程。

       调试不是测试
       调试过程从执行一个测试用例开始,评估测试结果,如果发现实际结果与预期结果不一致,则这种不一致就是一个症状,它表明在软件中存在着隐藏的问题。调试过程试图找出产生症状的原因,以便改正错误
       调试过程总会有以下两种结果之一:
            ①找到了问题的原因并把问题改正和排除掉了;
           ②没找出问题的原因。 在后一种情况下,调试人员可以猜想一个原因,并设计测试用例来验证这个假设,重复此过程直至找到原因并改正了错误
       调试工作如此困难,软件错误的下述特征也是相当重要的原因   
            (1)症状和产生症状的原因可能在程序中相距甚远,也就是说,症状可能出现在程序的一个部分,而实际的原因可能在与之相距很远的另一部分。紧耦合的程序结构更加剧了这种情况。   
            (2)当改正了另一个错误之后,症状可能暂时消失了。   
            (3)症状可能实际上并不是由错误引起的(例如,舍入误差)。   
            (4)症状可能是由不易跟踪的人为错误引起的。
            (5)症状可能是由定时问题而不是由处理问题引起的。   
            (6)可能很难重新产生完全一样的输入条件(例如,输入顺序不确定的实时应用系统)。   
            (7)症状可能时有时无,这种情况在硬件和软件紧密地耦合在一起的嵌入式系统中特别常见。   
            (8)症状可能是由分布在许多任务中的原因引起的,这些任务运行在不同的处理机上

调试途径

1.蛮干法

  • 蛮干法可能是寻找软件错误原因的最低效的方法。仅当所有其他方法都失败了的情况下,才应该使用这种方法。
  • 蛮干法按照“让计算机自己寻找错误”的策略,这种方法印出内存的内容,激活对运行过程的跟踪,并在程序中到处都写上 WRITE(输出)语句,希望在这样生成的信息海洋的某个地方发现错误原因的线索。
  • 在更多情况下这样做只会浪费时间和精力。在使用任何一种调试方法之前,必须首先进行周密的思考,必须有明确的目的,应该 尽量减少无关信息的数量

 2.回溯法

  • 回溯是一种相当常用的调试方法,当调试小程序时这种方法是有效的。具体做法:从发现症状的地方开始,人工沿程序的控制流往回追踪分析源程序代码,直到找出错误原因为止。
  • 随着程序规模的扩大,应该回溯的路径数目变得越来越大,回溯法不适用于这种规模的程序。

3.原因排错法   
       对分查找法、归纳法和演绎法都属于原因排除法。

  • 对分查找法的基本思路是,如果已经知道每个变量在程序内若干个关键点的正确值,则可以用赋值语句或输入语句在程序中点附近“ 注入”这些变量的正确值,然后运行程序并检查所得到的输出。
  • 归纳法是从个别现象推断出一般性结论的思维方法。使用这种方法调试程序时,首先把和错误有关的数据组织起来进行分析,以便发现可能的错误原因。然后导出对错误原因的一个或多个假设,并利用已有的数据来证明或排除这些假设。
  • 演绎法从一般原理或前提出发,经过排除和精化的过程推导出结论。采用这种方法调试程序时,首先设想出所有可能的出错原因,然后试图用测试来排除每一个假设的原因

软件可靠性

       软件可靠性是程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。
       一般说来,对于任何其故障是可以修复的系统,都应该同时使用可靠性和可用性衡量它的优劣程度。
       软件可用性是程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。
      可靠性和可用性之间的主要差别是,可靠性意味着在0到t这段时间间隔内系统没有失效,而可用性只意味着在时刻t,系统是 正常运行的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值