第 十 讲
编码与测试
本讲(第七章)的主要内容
? 编码
–编码的任务
–程序设计语言
–编码风格
? 软件测试基础
编码的任务
? 两个相关概念
– 实现,体现“如何做”的程序文本称为实现。
– 规范:,做什么”的形式化描述通常称为规范。
? 编码阶段的任务:
– 编写源程序( source code);
– 编写文档( document);
– 单元测试( unit testing)。
? 软件质量主要取决于设计的质量,但不能忽
略编码和程序设计语言的影响
? 编码需要遵循一定的标准,形成编码风格。
编码任务的流程
Pseudo
code
Source
code Debug
Test
LinkObject
code
Executable
code
Compile
Coding
微软开发的经验 ——注重标准
? Cusumano 和 Selby指出微软软件开发过程
中,在保留了开发人员展示自己的创造力
和个性的同时切实地融入软件工程概念。
? 微软开发小组都在各自独立的地方工作,
使用常用的开发语言,公共的开发风格,
标准的开发工具。
微软开发的经验 ——注重标准
? 标准有助于交流,讨论问题,解决问题。
– 微软要求各自的小组收集一系列测试结果,包括
出错信息和发现的潜在和修改了的错误。当继续
开发产品时,这些测试结果指导将来的决策。
? 标准有助于把设计转化为代码和软件重用。
– 按照标准把代码结构化,你可以保留代码和设计
中的相同部分。因此,设计的变化很容易在代码
中体现。
程序设计语言分类
? 机器语言 (Machine Language)
? 汇编 (Assemble Language)
? 高级语言
? 4GL
高级语言分类( 应用特点观)
? 基础语言,通用语言,应用广泛,如 BASIC、
FORTRAN等。
? 结构化语言,现代语言,提供结构化的控制
结构,支持很强的过程能力和数据结构能力。
如 PASCAL,C,Ada等。
? 专用语言,为某种特殊应用而设计的具有独
特语法形式的语言。如 APL用于向量运算;
LISP,PROLOG用于人工智能。
高级语言分类(内在特点观)
? 系统实现语言,利于系统软件的设计,灵活
的硬件资源管理 。
? 静态高级语言,静态地分配存储。
? 块结构高级语言,提供有限地动态存储分配。
? 动态高级语言,动态地完成所有存储管理。
程序设计语言的发展
参见 WORD表格
从多方面测度设计语言的特点
1,名字说明
2,类型说明
3,初始化
4,程序对象的局部性
5,程序的模块特性
6,循环控制结构
7,分支控制结构
8,异常处理
9,独立编译
设计语言特点之一:名字说明
? 名字说明的意义和作用
– 名字(如变量名,函数名等)说明是指预先说明
程序中所使用对象的名字,使得编译系统能够检
查出程序中这些名字使用的合法性。
– 利于排查错误,提高软件的可靠性。
? Fortran,Basic语言并不进行显式的名字
说明,会容易出现错误,或者错误难以
诊断 。
设计语言特点之二:类型说明
? 类型说明的意义
– 与名字说明的概念是一致的
– 可以借助于编译系统检查错误
– 预先说明数据类型有助于编译系统的类型检查,
减少歧义性
– 用户可以自定义数据类型
? Fortran语言规定,如果不显式地说明一
个变量,那么,这个变量名字的第一个
字母就隐含了该变量的类型。
设计语言特点之三:初始化
? 初始化的意义
– 减少程序出现错误的可能性。
– 提高系统的可靠性和安全性。
? 强迫程序员对变量进行初始化
– 如果引用之前没有初始化,系统会提示错误;
– 如果初始化之后没有被引用,系统也会提示
错误。
语言特点之四:程序对象的局部性
? 程序对象的局部性的意义
– 对变量、常量、函数等程序对象的说明该
靠近使用它的地方。
? 尽量使用局部的变量,以提高程序的可
读性和可修改性。
语言特点之五:程序模块
? 有关程序模块的一些概念
– 局部变量
– 全局变量( extern int x,y,其 作用域可以是
同一文件的多个函数 )
– 外部函数 (extern int function( ) 可以被其
它文件中的函数调用 )
– 内部函数 (static float function( ) 只能被同
一个文件的其它函数调用 )
计语言特点之六:循环控制
? 循环控制结构
– for语句
– while-do语句
– 需要在循环体内任意一点测试循环结束条件
(可以用 if-then-else实现; Ada提供了 exit语句,
exit{<标识符 >} {when <条件 >} )
语言特点之七:分支控制结构
? 分支控制结构
– if then else
– case (表达式)的两个问题:一是表达式的值不
在预定范围内;二是由表达式的值所选择的分支
取决于执行语句的排列次序。
– case (表达式),由表达式的值匹配 case标号选择
执行分支,与排列次序无关。允许缺省标号( C
语言的 default)或补缺标号 (Ada语言的 other)。
语言特点之八:异常处理
? 异常:程序执行过程中发生的错误或意外事件。
? 异常处理
– 是设计语言为程序员提供的一组处理异常情
况的功能。例如,PL/1,Ada语言提供了相
应的异常处理机制,当子程序或函数多层嵌
套调用时,可以将异常信息从一个函数方便
地传送到另一个函数。
语言特点之九:独立编译
? 独立编译的意义
– 独立编译是指能够分别编译各个程序单元,
然后再把他们集成为一个完整的程序。
– 只需要重新编译修改了的模块,然后重新连
接即可。例如对A模块的修改,如果不影响
到其它的模块,仅仅需要对A模块重新编译
即可。
? 对于大型软件来说,独立编译非常重要。
程序设计语言的选择
? 汇编语言
? 高级语言
高级语言的选择
? 总的要求
– 利于提高软件质量,降低开发成本
– 便于测试和维护;独立编译等
? 具体的实用标准
? 系统用户的要求,对效率的考虑。
? 可以使用的编译系统,目标系统的运行环境等。
? 可以利用的软件开发平台和开发工具。
? 软件工程的规模,算法和计算以及数据结构复杂性。
? 程序员的知识水平和喜好
? 软件的应用领域
? 软件可移植性要求
编码风格
1,程序内部的文档
2,数据说明的次序标准化
3,语句结构应该简洁明了
4,效 率
5,满足 human-engineering的 I/O风格
6,其它的风格
1,程序内部的文档( P137)
? 程序内部的文档包括意义明确的标识符、适当的注
释和标准化的书写格式等。
? 变量名、函数名、数据结构名等具有明显的意义,
可以提高程序的可读性,便于测试、维护。
? 注释要简明、适当和正确。序言性注释主要描述模
块的功能、主要算法、接口特点,重要的数据结构
说明等;与程序代码有关的注释要插在程序中对应
的位置,解释有关代码的作用和必要性。
? 程序清单的布局要有层次性,要求结构清晰。
2,数据说明的次序标准化
? 按照数据结构或数据类型确定说明的次序
? 对多个变量说明应该按照字母顺序排列
3,语句结构应该简洁明了( P138)
? 尽量使用三种基本结构,允许使用扩展的结构化
设计,尽量不用 GOTO语句(或局部性使用)。
? 每行只写一条语句。
? 尽量避免复杂的条件判断和对“非”条件的判断。
? 避免大量使用循环嵌套和条件嵌套。
? 善于使用括号使表达式次序清晰直观。
4,效率
? 程序运行时间( P139)
? 存储器效率
? 输入 /输出的效率
? 从效率第一到清晰第一(对大多数模块清晰
第一,个别模块效率第一)
5,满足 human-engineering的 I/O风格
? 对输入数据进行有效性检验,防止对程序的破坏。
? 对多个相关输入项进行组合检查,剔除似是而非
的输入值。
? 使用数据结束标记,不要要求用户用数据的数目
来控制。
? 交互式输入的提示清楚,尽量说明可用的选择或
边界数值。
? 程序设计语言对格式有严格要求时,应保持输入
格式一致。
? 为输出数据加标志或加以必要的说明以提醒读者。
? 保持输入格式简单;设计良好的输出报表。
6,其它的风格
? 对用户提供在线帮助。
? 对可能产生重大后果请求给出醒目提示,待用
户再次确认。
? 使程序具有“防弹 bulletproof‖功能,不至于因
用户的偶然错误使程序发生非正常的中断。
程序设计方法论
? 自顶向下
– 先实现软件结构的高层模块,再设计较低层次的模块
– 程序可读性较好,可靠性高
? 自底向上
– 先实现软件结构的低层模块,再设计较高层次的模块,
直至实现所有的模块
– 往往局部是优化的,但系统的整体结构较差。可以较
早发现关键算法的可行性,以避免较大的返工
程序设计自动化
? 由用户需求定义直接生成程序代码
? 利用各种通用模块进行组装
– 基于领域
– 模块独立性好(可理解性、功能可以预测,强内聚,
低耦合等
– 接口定义简单明了
– 模块库(构件库)丰富
? 扩展的自动化程序设计范型
– 基于知识的表达
– 非形式化规范到形式化规范
– 结合原型思想
程序设计工具
? 编译程序
– 诊断语法错误
– 生成高效率的机器代码
– 开发和优化编译程序
– 一般的语言系统还提供一些与编译系统联合使
用的交叉调试工具
? 代码管理系统
– 便于各类人员之间的协调(记录程序模块开发
和维护的历程,确定模块间的依赖关系)
– 保证同一系统不同版本中公共代码的一致
– 代码管理工具,如 UNIX/PWB系统中的 MAKE
和 SCCS。
软件测试基础
1,软件测试及其目标
2,软件测试准则
3,测试方法
4,测试步骤
5,测试阶段的信息流
1,Myers的软件测试的定义
? 测试是为了发现程序中的错误而执行程序
的过程;
? 好的测试方案是极可能发现迄今为止尚未
发现的错误的测试方案;
? 成功的测试是发现了迄今为止尚未发现的
错误的测试 。
测试的意义和几点说明
? 软件质量保证的最重要手段
– 是否达到需求说明的功能和预期的指标
? 测试耗时费力,应用最小的测试代价获得最大
的测试效果。
? 测试是为了发现错误,不是为了证明程序无错
误。
? 测试不能证明程序中没有错误。
? 测试的可信度( dependability)问题。
― Testing is the unavoidable part of any
responsible effort to develop a software
system.‖
— William Howden
― Optimism is the occupational hazard of
programming; testing is the treatment.‖
— Kent Beck
“Errors are more common,more
pervasive,and more troublesome in
software than other technologies.”
— David Parnas
― The first mistake that people make is
thinking that the testing team is
responsible for assuring quality.‖
— Brian Marick
―Every program does something right;
it just may not be the thing we want it
to do.‖
— we unknown
2,软件测试准则
? 所有的测试都应追溯到用户需求,从用户角度看,
最严重的错误是不能满足需求。
? 制定测试计划,并严格执行,排除随意性。测试
计划在需求分析阶段就开始了,详细的测试用例
在设计阶段确定。
? Pareto原则:所发现错误的 80%很可能源于程序模
块的 20%中。
? 测试应当从‘小规模’开始,逐步转向‘大规
模’。
? 穷举测试是不可能的( Exhaustive testing)。
? 由独立的第三方或专门的测试小组进行独立测试。
Cont.
? 测试用例由输入数据和相应的预期输出组成。
? 测试用例不仅选用合理的输入数据,还要选择不
合理的。
? 不仅检查程序是否做了应该做的事,还应该检查
是否不应该做的。
? 长期保留测试用例,以便进行回归测试和维护。
3,测试技术的分类
? 静态测试
– 代码会审 code inspection
– 走查 walk-through
– 办公桌检查 desk checking
– 例如,Yourdon结构化走通,IBM的 Fagan检查
? 动态测试
– 黑盒测试
– 白盒测试
– 穷举和选择测试。
静态测试
? 定义,人工方式进行的代码复审。又称 人工测试,
代码复审。
? 目的:检查程序的静态结构,找出编译不能发现
的错误和人的主观认识上的偏差。
? 范围:需求定义、设计文档、源代码(着重分析)
? 特点:
– Myers的研究表明,对于某些类型的错误,静态
测试更有效 。
– 经验表明,组织良好的代码复审可以发现程序
中 30%到 70%的编码和逻辑设计错误。
– 不存在错误定位问题。
动态测试
? 定义, 机器测试,在设定的测试数据上执行被
测试程序的过程。
? 目的, 通过执行程序代码动态地验证结果的正
确性。
? 三个过程, 设计测试用例;执行被测试程序;
分析执行结果并发现错误。
? 三个要素,程序、测试数据、需求定义
? 两个方面, 在测试数据上程序是对的;测试
数据是正确的。
黑盒测试( Black-Box Testing)
? 定义
– 已知产品应该具有的功能,通过测试检验其
每个功能是否都能够正常使用。又称功能测

? 用途
– 把程序看成一个黑盒子,仅仅考虑输入和输
出的对应关系和程序接口,完全不考虑它的
内部结构和处理过程。一般用于综合测试、
系统测试等
白盒测试 ( White-Box Testing)
? 定义
– 已知产品内部的工作过程,通过测试检验产
品内部动作是否都能按照需求定义的规定正
常使用。又称 Glass box testing,结构测试。
? 用途
– 必须完全了解程序的内部结构和处理过程,
才能按照程序内部的逻辑测试,以检验程序
中每条路径是否正确,因此 一般用于规模较
小软件。
穷举测试( Exhaustive Testing)
? 定义:包含所有可能情况的测试。
? 对于黑盒测试,必须对所有输入数据的各
种可能值的排列组合都进行测试;
? 对于白盒测试,程序中每条可能的路径在
每种可能的输入数据下至少执行一次。
? 穷举测试是不可能的
– 例一:要对 C编译系统进行黑盒穷举测试,一方面
要编出所有能够想象出来的合法程序让它编译;
另一方面又要编出一切不合法的程序,考察它能
否指出程序的非法性质。显然,这两类(合法和
不合法)程序的数量是无限的。
选择测试
? 仅选择一些具有代表的、典型的测试
用例,进行有限的测试。
? 以最少的测试用例发现最多的程序错
误。
4,软件测试的阶段
? 单元测试 (模块测试):目的是保证每个模块
作为一个单元能正确运行。主要测试编码和详
细设计阶段的错误。
? 子系统测试,把经过单元测试的模块放在一起
形成子系统。注重模块接口。
? 系统测试 (集成测试):测试由子系统组成的
整个系统,不仅测试模块间的协调和通信能力。
还要测试设计错误、需求说明中的功能错误。
? 验收测试,确认系统能够满足用户的需求,方
法同系统测试,主要强调用户的参与( alpha测
试),测试需求说明中的功能错误。
? 平行运行, beta测试
5,测试阶段的信息流程
正确
可靠性
错误
错误率数据
预期结果
测试结果
测试配置
软件配置
测试 评价
调试
可靠性
模型