七、实现
编码
编码是把软件设计结果翻译成用程序设计语言书写的程序,是对设计的进一步具体化,因此程序的质量主要取决于软件设计的质量。
选择程序设计语言
理想标准:
① 选用高级语言编写写程序。
② 选用的高级语言应该有理想的模块化机制,以及可读性好的控制结构和数据结构。
③ 选用语言特点应该使编译程序能够尽可能多地发现程序中的错误。
④ 选用的高级语言应该有良好的独立编译机制。
但是在实际选择语言的时候还要考虑种种限制,所以下面是实用标准
- 系统用户的要求
- 可以使用的编译程序
- 可以得到的软件工具
- 工程规模
- 程序员的知识
- 软件可移植性要求
- 软件的应用领域
编码风格
源程序代码的逻辑简明清晰、易读易懂是好程序的一个重要标准,为了做到这一点应该遵循下列原则。
(1)程序内部的文档
① 定义
程序内部的文档包括恰当的标识符、适当的注解和程序的视觉组织等。
② 命名规则
a. 选取含义鲜明的名字,使它能正确地提示程序对象所代表的实体。
b. 使用缩写时,缩写规则应该一致,并且应该给每个名字加注解。
③ 注释规则
a. 在每个模块开始处应有序言性注解,简述功能、算法、接口、重要数据和开发简史。
b. 程序中间应有一段与代码有关的注解,主要解释代码的必要性。
c. 对于用高级语言书写的源程序,应该利用注解提供一些额外的信息。
d. 应该用空格或空行清楚地区分注解和程序。
e. 注解的内容一定要正确,错误的注解会妨碍对程序的理解。
④程序清单的布局规则
应利用适当的阶梯形式使程序的层次结构清晰明显。
(2)数据说明
为了使数据更容易理解和维护,应该遵循一些简单的原则如下。
① 数据说明的次序应该标准化。有次序就容易査阅,因此能够加速测试、调试和维护的过程。
② 多个变量名在一个语句中说明时,应该按字母顺序排列这些变量。
③ 使用复杂的数据结构,应用注解说明用设计语言实现这个数据结构的方法和特点。
(3)语句构造
构造语句应该遵循的原则是,每个语句都应该简单而直接,不能为了提高效率而使程序变得过分复杂。要遵循以下规则。
a. 不要为了节省空间而把多个语句写在同一行。
b. 尽量避免复杂的条件测试。
c. 尽量减少对“非”条件的测试。
d. 避免大量使用循环嵌套和条件嵌套。
e. 利用括号使逻辑表达式或算术表达式的运算次序清晰直观。
(4)输入输出
① 对所有输入数据都进行检验。
② 检査输入项重要组合的合法性。
③ 保持输入格式简单。
④ 使用数据结束标记,不要要求用户指定数据的数目。
⑤ 明确提示交互式输入的请求,详细说明可用的选择或边界数值。
⑥ 当程序设计语言对格式有严格要求时,应保持输入格式一致。
⑦ 设计良好的输出报表。
⑧ 给所有输出数据加标志。
(5)效率
效率主要指处理机时间和存储器容量两个方面。
原则:
- 效率是性能要求,在需求分析阶段确定效率方面的要求
- 软件应该像对它要求的那样有效,而不应该如同人类可能做到的那样有效
- 程序的效率和程序的简单程度是一致的,不要牺牲清晰性和可读性提高不必要的效率。
应该从三个方面讨效率问题
- 程序运行时间
- 存储器效率
- 输入输出效率
软件测试基础
软件测试阶段的根本目标是尽可能多地发现并排除软件中潜藏的任务,最终把一个高质量的软件系统交给用户使用。
测试的规则(定义):
(1)测试是为了发现程序中的错误而执行程序的过程。
(2)好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案。
(3)成功的测试是发现了至今为止尚未发现的错误的测试。
测试不能证明程序是正确的。
测试准则:
(1) 所有测试都应该能追溯到用户需求。
(2) 应该远在测试开始之前就制定出测试计划。
(3) 应用Pareto原理,即测试发现的错误中80%可能是由程序20%的模块造成的。
(4) 应该从“小规模”测试开始,并逐步进行“大规模”测试。
(5) 穷举测试是不可能的,即测试只能证明程序中有错误,不能证明程序中没有错误。
(6) 为了达到最佳的测试效果,应该由独立的第三方从事测试工作。
方法:
- 黑盒测试(完全不考虑程序内部结构和处理过程,只检查功能,它称作功能测试)
- 白盒测试(测试者完全知道程序的结构和处理算法,按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按照预定要求正确工作)
步骤:
- 模块测试(保证每一个模块作为一个单元能正确运行)
- 子系统测试(把模块放在一起形成一个子系统来测试,这个步骤着重测试接口)
- 系统测试(将经过测试的子系统装配成完整系统进行测试)
- 验收测试(把系统作为单一实体进行测试,是用户积极参与进行的,主要使用实际数据进行测试)
- 平行运行(验收后不立即投入生产性运行,要经过一段平行运行时间考验)
测试阶段的信息流
单元测试
单元测试主要测试模块。一般在编写完程序代码并通过编译时就可以对程序重要通路进行测试。一般采用人工测试和计算机测试两种不同类型的测试方法。
主要应对以下五个模块进行测试
- 模块接口
- 局部数据结构
- 重要执行通路
- 出错处理通路
- 边界条件
代码审查
人工测试源程序可以由程序的编写者本人非正式地进行,也可以由审査小组正式进行。后者称为代码审査,是一种非常有效的程序验证技术。
流程
- 组建审查小组(组长、程序设计者、程序编写者、程序测试者组成)
- 审查会议
优点
- 一次审查会上可以发现很多错误
- 不需要每发现一个错误就进行改正,提升工作效率
与计算机测试相辅相成,互相补充
计算机测试
模块并不是一个独立的程序,必须要为每个单元测试开发驱动软件和存根软件,具体如下:
-
驱动程序
接收测试数据,把这些数据传送给被测试的模块,并印出有关结果
-
存根程序
代替被测试的模块所调用的模块,它使用被它代替的模块的接口,做最少量的数据操作,印出对入口的检验或操作结果,并且把控制归还给调用它的模块。
集成测试
集成测试试测试和组装软件的系统化技术其主要目标是发现与接口有关的问题。
模块组装成程序有两种方法:
① 非渐增式测试
先分别测试每个模块,再把所有模块按设计要求放在一起结合成所要的程序。
缺点:
① 把所有模块放在一起,测试者面对的情况十分复杂。
② 在庞大的程序中诊断定位一个错误非常困难。
③ 一旦改正一个错误之后,又会遇到新的错误,没有穷尽。
② 渐增式测试
把下一个要测试的模块同已经测试好的那些模块结合起来进行测试,测试完以后再把下一个应该测试的模块结合进来测试,每次增加一个模块。渐增式测试同时完成单元测试和集成测试。
渐增式测试拥有自顶向下和自底向上两种策略。
自顶向下集成
方式:深度优先,宽度优先。
步骤:
a. 对主控制模块进行测试,测试时用存根程序代替所有直接附属于主控制模块的模块。
b. 根据选的结合策略(深度优先或宽度优先),每次用一个实际模块代换一个存根程序。
c. 在结合进一个模块的同时进行测试。
d. 为了保证加入模块没有引进新的错误,可能需要进行回归测试。
自底向上测试
自底向上测试从软件结构最低层的模块开始组装和测试。因为是从底部向上结合模块,总能得到所需的下层模块处理功能,所以不需要存根程序。
步骤:
a. 把低层模块组合成实现某个特定的软件子功能的族。
b. 写一个用于测试的控制程序,协调测试数据的输入和输出。
c. 对由模块组成的子功能族进行测试。
d. 去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来形成大的子功能族。
两种方式的比较
(1)自顶向下集成
① 优点
a. 不需要测试驱动程序。
b. 能够在测试阶段的早期实现并验证系统的主要功能。
c. 能在早期发现上层模块的接口错误。
② 缺点
a. 需要存根程序,可能遇到与此相联系的测试困难。
b. 低层关键模块中的错误发现较晚。
c. 在早期不能充分展开人力。
(2)自底向上集成
① 优点
a. 不需要存根程序,不会遇到与存根程序相联系的测试困难。
b. 能较早的发现低层关键模块的错误。
c. 能在早期充分展开人力。
② 缺点
a. 需要测试驱动程序。
b. 不能在测试阶段早期实现并验证系统的主要功能。
c. 在早期不能发现上层模块的接口错误。
其他的集成测试策略
在测试实际的软件系统时,应该根据软件的特点以及工程进度安排,选用适当的测试策略。一般说来,纯粹
自顶向下或纯粹自底向上的策略可能都不实用,人们在实践中创造出许多混合策略。
(1) 改进的自顶向下测试方法
基本上使用自顶向下的测试方法,但在早期使用自底向上的方法测试软件中的少数关键模块。缺点是测试关
键模块时需要驱动程序。
(2) 混合法
对软件结构中较上层使用的自顶向下方法与对软件结构中较下层使用的自底向上方法相结合。
回归测试
回归测试用于保证由于调试或其他原因引起的变化,不会导致非预期的变化。
通俗点说就是我这新引入一模块,别把之前我检测没问题的模块影响了,我引入新模块之后得回去康康我之前引入的有没有受影响。
方法:
① 通过重新执行全部测试用例的一个子集人工地进行。
② 利用捕获回放工具,捕获测试用例和实际运行结果,然后回放,并比较运行结果。
一般其包括下面三类不同的测试用例:
① 检测软件全部功能的代表性测试用例。
② 专门针对可能受修改影响的软件功能的附加测试。
③ 针对被修改过的软件成分的测试。
确认测试
确认测试也称为验收测试,它的目标是验证软件的有效性。
要求:
① 必须有用户积极参与,或者以用户为主进行。用户应该参与设计测试方案,使用用户界面输入测试数据并
且分析评价测试的输出结果。在验收之前由开发单位对用户进行培训。
② 确认测试通常使用黑盒测试法。应该仔细设计测试计划和测试过程,测试计划包括要进行的测试的种类及
进度安排,测试过程规定了用来检测软件是否与需求一致的测试方案。通过测试和调试要保证软件能满足所有功能要求。
确认测试通常使用黑盒测试法。确认测试有下述两种可能的结果:
① 功能和性能与用户要求一致,软件是可以接受的。
② 功能和性能与用户要求有差距。
软件配置复查
其目的是保证软件配置的所有成分都齐全,质量符合要求,文档与程序完全一致。
Alpha和Beta测试
(1)Alpha测试
Alpha测试由用户在开发者的场所进行,并且在开发者对用户的“指导"下进行测试,且开发者负责记录发现的错误和遇到的问题。即心ha测试是在受控的环境中进行的。
(2) Beta 测试
Beta测试由软件的最终用户们在一个或多个客户场所进行。开发者通常不在Beta测试的现场,即Beta测试
是软件在开发者不能控制的环境中的“真实”应用。
白盒测试技术
逻辑覆盖
分为以下几种:
语句覆盖:
选择足够多的的测试数据使得程序中每个语句至少被执行一次。
它是很弱的逻辑覆盖标准
判定覆盖:
又叫分支覆盖,它的意思是不仅每个语句都至少被执行一次而且判定的每种可能的结果也都应该至少被执行一次。
判定覆盖比语句覆盖稍微强点,但也强不到哪儿去。
条件覆盖:
不仅每个语句至少执行一次,而且每个条件都取到各种可能的结果。
条件覆盖通常比判定逻辑强,但也不能覆盖所有情况。
判定覆盖只关心判定表达式的值(真/假),而条件覆盖涉及到判定表达式的每个条件的值(真/假)。
判定/条件覆盖:
同时满足判定覆盖和逻辑覆盖两种情况。
但是有时候判断/条件覆盖也并不比条件覆盖更强。
条件组合覆盖:
条件组合覆盖是更强的逻辑覆盖标准,它要求选取足够多的测试数据,使每个判定表达式中的条件组合的各种可能都至少出现一次。
条件组合覆盖是前述几种覆盖标准中最强的,但是满足条件组合的覆盖标准的测试数据并不能使程序每条路径都执行到。
点覆盖
连通图G的子图G,是连通的,而且包含G的所有结点,则称G,是G的点覆盖。满足点覆盖标准要求选取足
够多的测试数据,使得程序执行路径至少经过流图的每个结点一次,即点覆盖标准和语句覆盖标准是相同的。
边覆盖
连通图G的子图G”是连通的,而且包含G的所有边,贝!)称G”是G的边覆盖。为满足边覆盖的测试标准,
要求选取足够多测试数据,使程序执行路径至少经过流图中每条边一次,即边覆盖与判定覆盖是相同的。
路径覆盖
路径覆盖含义是选取足够多测试数据,使程序的每条可能路径都至少执行一次,如果程序图中有环,则要求
每个环至少经过一次。
控制结构测试
(1)基本路径测试
步骤:
-
根据过程设计结果画出相应的流图
-
计算流图环形复杂度
-
确定线性独立路径的基本集合(至少包含一条在定义该路径之前不曾用过的边)
独立路径是指至少引入程序的一个新处理语句集合或一个新条件的路径。
-
设计可强制执行基本集合中每条路径的测试用例
(2)条件测试
用条件测试技术设计出的测试用例,能够检查程序模块中包含的逻辑条件。
条件测试的优点
a. 容易度量条件的测试覆盖率。
b. 程序内条件的测试覆盖率可指导附加测试的设计。
条件测试的目的
条件测试的目的不仅是检测程序条件中的错误,而且是检测程序中的其他错误。
(3)循环测试
循环测试专注于测试循环结构的有效性。在结构化的程序中通常只有三种循环即简单循环、串接循环和嵌套循环。
嵌套循环可以通过以下步骤减少测试数:
第一,从最内层循环开始测试,把所有其他循环都设置为最小值。
第二,对最内层循环使用简单循环测试方法。使内层循环的迭代参数取最小值,并为越界值或非法值增加一
些额外的测试。
第三,由内向外,对下一个循环进行测试,但保持所有其他外层循环为最小值,其他嵌套循环为“典型”值。
第四,继续进行下去,直到完成所有循环。
串接循环
如果串接循环的各个循环都彼此独立,则可以使用前述的测试简单循环的方法来测
试串接循环;循环不独立时,使用测试嵌套循环的方法来测试串接循环。
黑盒测试技术
黑盒测试着重测试软件功能。黑盒测试并不能取代白盒测试,它是与白盒测试互补的测试方法,它很可能发现白盒测试不易发现的其他类型的错误。
(1) 目的
黑盒测试力图发现下述类型的错误:
① 功能不正确或遗漏了功能。
② 界面错误。
③ 数据结构错误或外部数据库访问错误。
④ 性能错误。
⑤ 初始化和终止错误。
(2) 适用性
白盒测试在测试过程的早期阶段进行,黑盒测试主要用于测试过程的后期进行。
等价划分
等价划分是一种黑盒测试技术,它把程序的输入域划分为若干个数据类。
划分数据等价类:
第一,需要研究程序的功能说明,从而确定输入数据的有效等价类和无效等价类。
第二,在确定输入数据的等价类时常常还需要分析输出数据的等价类。
第三,在划分等价类时还应考虑编译程序的检错功能。
等价类划分规则:
a. 如果规定了输入值的范围,则可划分一个有效的等价类(输入值在此范围内),两个无效的等价类(输入
值小于最小值或大于最大值)。
b. 如果规定了输入数据的个数,则类似地也可以划分出一个有效的等价类和两个无效的等价类。
c. 如果规定了输入数据的一组值,而且程序对不同输入值做不同处理,则每个允许的输入值是一个有效的
等价类,此外还有一个无效的等价类(任一个不允许的输入值)。
d. 如果规定了输入数据必须遵循的规则,则可以划分出一个有效的等价类(符合规则)和若干个无效的等
价类(从各种不同角度违反规则)。
e. 如果规定了输入数据为整型,则可以划分出正整数、零和负整数3个有效类。
f. 如果程序的处理对象是表格,则应该使用空表,以及含一项或多项的表。
在第173页有一个例子,大家可以参考一下。
边界值分析
使用边界值分析方法设计测试方案首先应该确定边界情况,选取的数据应该刚好等于、稍小于和稍大于等价
类边界值,即应该选取刚好等于、稍小于和稍大于等价类边界值的数据作为测试数据,而不是选取每个等价类内的典型值或任意值作为测试数据。
错误推测
错误推测法基本思想是列举出程序中可能有的错误和容易发生错误的特殊情况,并且根据它们选择测试方案。
调试
调试是在测试发现错误之后排除错误的过程。
流程:
调试会有两种结果之一: 找到问题并且更正问题了、没找出问题。
调试途径:
(1)蛮干法
① 基本思路
按照“让计算机自己寻找错误”的策略,这种方法印出内存的内容,**对运行过程的跟踪,并在程序中到处都写上WRITE (输出)语句,在生成的信息海洋的某个地方发现错误原因的线索。
② 适用性
蛮干法是寻找软件错误原因的最低效的方法。仅当所有其他方法都失败了的情况下,才应该使用这种方法。
(2) 回溯法
① 基本思路
从发现症状的地方开始,人工沿程序的控制流往回追踪分析源程序代码,直到找出错误原因为止。
② 适用性
当调试小程序时回溯法非常有效的。但随着程序规模的扩大,应该回溯的路径数目也变得越来越大,以至彻底回溯变成完全不可能了。
(3) 原因排除法
包括对分查找法、归纳法和演绎法。
软件可靠性
(1) 软件可靠性
软件可靠性是程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。
(2) 软件的可用性
软件可用性是程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。
(3) 比较
① 可靠性意味着在0到t这段时间间隔内系统没有失效。
② 可用性只意味着在时刻t,系统是正常运行的。
(4) MTTF 和 MTTR
① 概念
a. 平均维修时间MTTR
表示修复一个故障平均需要用的时间,取决于维护人员的技术水平和对系统的熟悉程度,也和系统的可维护
性有重要关系。
b. 平均无故障时间MTTF
表示系统按规格说明书规定成功地运行的平均时间,主要取决于系统中潜伏的错误的数目,因此和测试的关
系十分密切。
② 计算公式
系统稳态可用性Ass为
下面估算平均无故障时间的方法大家自行看看,由于公式太多这里就不写了。
习题
这里基本都是应用题这种,大家自己写一写吧