《通常把编码和测试统称为实现》由会员分享,可在线阅读,更多相关《通常把编码和测试统称为实现(98页珍藏版)》请在金锄头文库上搜索。
1、通常把编码和测试统称为实现。 编码就是把软件设计结果翻译成用某种程序设计语言书写的程序。 测试的目的就是在软件投入生产性运行之前,尽可能多地发现软件中的错误。,第七章 实现,软件测试在软件生命周期中横跨两个阶段。 单元测试:通常在编写出每个模块之后就对它做必要的测试(称为单元测试),模块的编写者和测试者是同一个人,编码和单元测试属于软件生命周期的同一个阶段。 综合测试:在这个阶段结束之后,对软件系统还应该进行各种综合测试,这是软件生命周期中的另一个独立的阶段,通常由专门的测试人员承担这项工作。 大量统计资料表明,软件测试的工作量往往占软件开发总工作量的40%以上。,7.1.1 程序设计语言,7
2、.1 编码,1 程序设计语言的分类,大体上,程序设计语言分为以下几类: (1)机器语言 (2)汇编语言 (3)高级语言,由于高级语言种类繁多,我们可以从应用特点、语言内在特点和对客观系统的描述三个不同的角度来对高级语言进行分类。,(1)基础语言(例:FORTRAN,BASIC,COBOL和ALGOL) (2)结构化语言(例:ALGOL,PL/1,PASCAL,C,Ada) (3)专用语言(例:APL,LISP,PROLOG,BLISS,FORTH),1)、从应用特点的角度来分,(1)系统实现语言(例:C语言) (2)静态高级语言(例:FORTRAN、COBOL) (3)块结构高级语言(例:PA
3、SCAL,ALGOL) (4)动态高级语言,2)、从语言内在特点的角度来分,(2)面向对象语言 对象+消息,(1)面向过程语言 数据结构+算法,3)、从描述客观系统的角度来分,例:Delphi、Visual Basic、JAVA、C+。,2 程序设计语言的特点,1名字说明 2类型说明 3选择控制结构 4循环控制结构 5程序对象的局部性 6变量的局部共享 7异常处理 8独立编译,3 程序设计语言的选择,一般情况下,我们采用高级语言来编程。 选择具体高级语言类型的原则: (1)系统的应用领域 (2)用户的要求 (3)软件的执行环境 (4)目标系统的性能要求 (5)程序员的知识水平 (6)软件的可移
4、植性要求,程序内部的文档包括: 1) 恰当的标识符(变量和标号)的名字; 2) 适当的注释; 3) 程序的视觉组织。,1 程序内部的文档,7.1.2 编码风格,为了使数据更容易理解和维护,应遵循一些简单的原则: (1)数据说明的次序应当规范化。 (2)当多个变量名在一个语句中说明时,应该按字母顺序排列这些变量。 (3)如果设计时使用了一个复杂的数据结构,则应注解说明用程序设计语言实现这个数据结构的方法和特点。,2 数据说明,语句构造应遵循的原则是:每条语句应该简单而直接,不应为了片面追求效率而使代码变得过于复杂。,3 语句构造,人们在长期的实践中总结了以下一些规则: 不要为了节省空间而把多个语
5、句写在同一行; 用空格或可读的符号使语句的内容更加清晰; 尽量避免复杂的条件测试; 尽量避免使用“非”条件的条件语句; 避免过多使用循环嵌套和条件嵌套; 利用括号使逻辑表达式或算术表达式的运算次序清晰直观; 尽可能使用库函数; 让编译程序作简单的优化。,在设计和程序编码时,应考虑输入和输出风格原则: 对所有输入数据都进行校验,以保证每个数据的有效性; 检查重要的输入项组合的合法性; 使得输入的步骤和操作尽可能简单,并保持简单的输入格式; 输入一批数据时,使用输入结束指示符,不要要求用户说明输入项数; 在以交互式输入输出方式进行输入时,要指明可以使用的选择值或界限值; 应允许缺省值; 当程序设计
6、语言对输入输出格式有严格要求时,应保持输入格式与输入语句的要求一致; 给所有的输出加注释,并设计输出报表格式。,4 输入输出,通常,效率主要指占用处理机时间和主存区域两个方面。好的编码可以提高效率,在我们进一步讨论这个问题之前,应该记住三条原则: 第一、效率是一个性能要求,因而应该在需求分析阶段确定代码效率方面的要求; 第二、通过好的设计可以提高效率; 第三、程序的效率和程序的简明程度是一致的,不应该为了提高代码效率而牺牲程序的清晰性和可读性。,5 效率,1)、代码效率,2)、存储效率,3)、输入输出的效率,为了提高编码的效率,保证程序的可靠性,我们经常使用一些编码工具。 首先要用的当然是编辑
7、工具了。选用合适的编辑工具可以大大方便编程,提高效率。 编译程序的好坏也会影响编码的效率。一方面,好的编译程序应该是程序员的好助手,能够帮助程序员及时准确地诊断出程序中的差错,减少程序开发的成本。另一方面,编译程序还应该能够生成高效率的机器代码,也就是代码优化。,编码工具,7.2 软件测试基础,关于测试目的,G.Myers给出了以下的观点:,(1)测试是为了发现程序中的错误而执行程序的过程; (2)好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案; (3)成功的测试是发现了至今为止尚未发现的错误的测试。,测试的定义:为了发现程序中的错误而执行程序的过程。具体地说,软件测试是根据软件开发
8、各阶段的规格说明和程序的内部结构而精心设计出一批测试用例,并利用测试用例来运行程序,以发现程序错误的过程。,7.2.1 软件测试的定义,7.2.2 软件测试的基本原则,(1)尽早地、不断地进行软件测试。 (2)设计测试用例时,要给出测试的预期结果。 (3)开发小组和测试小组分开。 (4)要设计非法输入的测试用例。 (5)在对程序修改之后要进行回归测试。 (6)程序中尚未发现的错误的数量往往与在该段程序中已发现的错误的数量成正比。,7.2.3 软件测试的方法,测试任何产品都有两种方法:如果已经知道了产品应该具有的功能,可以通过测试来检验是否每个功能都能正常使用,这种方法称为黑盒测试; 如果知道产
9、品的内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常进行,这种方法称为白盒测试。,大型软件系统通常由若干个子系统组成,每个子系统又由许多模块组成,因此,测试过程也必须分步骤进行,后一个步骤在逻辑上是前一个步骤的继续。 大型软件系统的测试过程基本上由下述几个步骤组成。,7.2.4 软件测试的步骤,1单元测试 又称模块测试。每个程序模块完成一个相对独立的子功能,所以可以对该模块进行单独的测试。由于每个模块都有清晰定义的功能,所以通常比较容易设计相应的测试方案,以检验每个模块的正确性。,2. 子系统测试子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间的
10、协调和通信是这个测试过程中的主要问题,因此,这个步骤着重测试模块的接口。,3. 系统测试 系统测试是把经过测试的子系统装配成一个完整的系统来测试。在这个过程中不仅应该发现设计和编码的错误,还应该验证系统确实能提供需求说明书中指定的功能,而且系统的动态特性也符合预定要求。在这个测试步骤中发现的往往是软件设计中的错误,也可能发现需求说明中的错误。 不论是子系统测试还是系统测试,都兼有检测和组装两重含义,通常称为集成测试。,4. 验收测试 验收测试把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但是它是在用户积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的信息)进行测试。验
11、收测试的目的是验证系统确实能够满足用户的需要,在这个测试步骤中发现的往往是系统需求说明书中的错误。验收测试也称为确认测试。,5. 平行运行 所谓平行运行就是同时运行新开发出来的系统和将被它取代的旧系统,以便比较新旧两个系统的处理结果。 这样做的具体目的有如下几点: (1) 可以在准生产环境中运行新系统而又不冒风险; (2) 用户能有一段熟悉新系统的时间; (3) 可以验证用户指南和使用手册之类的文档; (4) 能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标。,7.2.5 软件测试信息流,单元测试又称模块测试,集中对软件设计的最小单位模块进行测试,主要是为了发现模块内部可能存
12、在的各种错误和不足。 进行单元测试时,根据程序的内部结构设计测试用例,主要使用白盒测试法。由于各模块间相对独立,因而对多个模块的测试可以并行地进行,以提高测试效率。,7.3 单元测试,软件测试的步骤,1、单元测试的内容,(1)模块接口 主要进行的测试项目有以下几方面: 所测模块的形式参数和调用该模块的实际输入参数在参数数目、属性和顺序上是否匹配; 是否修改了只做输入用的形式参数; 输出给被调用模块的参数在数目、属性和顺序上是否正确; 全程变量的定义和用法在各个模块中是否一致。 若模块中有外部的I/O操作,还应该进行以下的测试项目: 文件属性是否正确; 打开文件语句和关闭语句是否正确; 格式说明
13、书与输入输出语句是否一致; 缓冲区的大小与记录长度是否匹配; 使用文件之前是否先打开了文件; 文件操作结束后是否关闭了文件; 是否进行了输入输出错误检查并进行了相应的处理。,(2)局部数据结构,模块的局部数据结构是常见的错误来源,测试者应该仔细设计测试用例,以便发现这样一些类型的错误: 错误的变量名(变量名拼写错或被编译程序截短); 错误的或不一致的数据类型说明; 使用尚未赋值或尚未初始化的变量; 错误的初始值或错误的缺省值; 数据类型不相容; 上溢、下溢或地址异常。 如果有可能的话,在单元测试期间除了局部数据结构之外,还应该检查全程数据对模块的影响。,(3)重要的执行路径,选择适当的测试用例
14、,对模块中的最有代表性、最可能发现错误的执行路径进行测试。 错误的计算主要集中在以下几个方面: 运算的优先次序不对或误解了运算符的优先次序; 混合运算(运算对象的类型彼此不相容); 变量的初始值赋值不正确; 运算的精度不够; 表达式的符号有错误。 错误的比较和控制流主要集中在以下几个方面: 不同数据类型之间的比较; 逻辑运算符不正确或优先次序不正确; 由于精度问题造成的两值比较时不相等; 差“1”错,即循环次数多一次或少一次; 错误的或不可能的循环终止条件; 当遇到发散的迭代时不能终止的循环; 错误地修改循环变量。,(4)出错处理,由于输入等条件的限制,程序在运行中出错往往是不可避免的。因而好
15、的程序设计应该能预见可能出现的各种出错情况,并且设置相应的出错处理,以便在出现错误时执行相应的操作。 在单元测试时也应该对模块中的出错处理部分进行测试,进行这一部分测试时可能存在的错误主要有: 对错误的描述难于理解,或者是描述过于简单; 显示的错误信息与实际错误不相符; 在对错误进行处理之前,错误条件已经引起系统的干预; 对错误的处理不正确。,(5)边界条件,我们知道,软件常常在它的边界上失效。例如,处理n元数组的第一个元素或最后一个元素时,在n次循环中的第n次重复时,往往会发生错误。因此,使用刚好小于、等于或大于最大值或最小值的数据结构、控制量和数据值的测试方案时,很可能会发现软件中的错误。
16、,2、单元测试的步骤,单元测试的对象是模块。测试者必须自己动手设计这两类模块:驱动模块和存根模块。,驱动模块:相当于所测模块的“主程序”。它接收测试数据,把这些数据传送给所测模块,然后输出测试结果。 存根模块:也叫虚拟子程序。它的作用是模拟被测模块所调用的子模块。存根模块可以做少量的数据操作,一般情况下,不需要把实际子模块的所有功能都带进来。,7.4 集成测试,集成测试过程中要考虑的问题: (1)数据穿过模块接口时是否会丢失; (2)模块的功能是否会对其它模块的功能产生不利的影响; (3)把子功能组合起来,能否达到预期的主功能要求; (4)单个模块的误差累积起来是否会放大到不能接受的程度; (5)全局数据结构是否有问题。,将各个模块组装成系统的方法:非增殖式组装方式和增殖式组装方式。,采用非增殖式组装方式:先分别对每个模块进行测试,再把所有模块按设计要求组装在一起进行测试,最终得到所要求的软件。 采用增殖式组装方式:把下一个要测试的模块同已经测试好的那些模块结合起来进行测试,测试完以后再把下一个应该测试的模块结合进来测试,这种方法实际上同时完成单元测试和集成测试。,