[TOC]
软件 = 程序 + 数据 + 文档
软件工程方法学【范型】三要素:方法、工具、过程
两个方法学:
- 传统方法学【生命周期方法学 结构化范型】
- 面向对象方法学 【都是对象】
- 对象
- 类(数据/属性,操作/方法)
- 继承,封装,多态
软件危机
是指在计算机软件的开发和维护过程中所遇到的一系列严重问题,这些问题不仅是不能正常运行的软件才具有的,实际上几乎所有的软件都不同程度地存在这些问题。
两个方面:开发与维护。
原因:与软件本身的特点有关;和软件开发与维护的方法不正确有关。
软件工程
指导计算机软件开发和维护的工程学科。采用工程的概念、原理、技术和方法来开发与维护软件,把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来,以经济地开发出高质量的软件并有效地维护它
软件生命周期的基本任务、三个时期的八个阶段
软件定义期:包括问题定义、可行性研究、需求分析;
任务:确定软件开发工程必须完成的总目标;确定工程的可行性;导出实现工程目标应该采用的策略及系统必须完成的功能;估计完成该项工程需要的资源和成本,并且制定工程进度表。
软件开发期:包括概要设计、详细设计、实现、测试;
任务:具体设计和实现在前一个时期定义的软件
运行维护期,即运行维护阶段。
任务:使软件持久地满足用户的需求。
1.问题定义:要解决的问题是什么
2.可行性研究:问题定义阶段所确定的问题是否有行得通的解决办法
3.需求分析:目标系统必须做什么,这个阶段的另外一项重要任务,是用正式文档准确地记录对目标系统的需求,这份文档通常称为软件需求规格说明书
4.概要设计:怎样实现目标系统,概要设计又称为初步设计、逻辑设计、高层设计或总体设计。概要设计的另一项主要任务就是设计程序的体系结构,也就是确定程序由哪些模块组成以及模块间的关系。
5.详细设计:应该怎样具体地实现这个系统,这个阶段的任务还不是编写程序,而是设计出程序的详细规格说明
6.编码和单元测试:写出正确的容易理解、容易维护的程序模块,验证模块正确性;
7.综合测试:通过各种类型的测试(及相应的调试)使软件达到预定的要求
8.软件维护:通过各种必要的维护活动使系统持久地满足用户的需要。|| 通常有四类维护活动:改正性维护,也就是诊断和改正在使用过程中发现的软件错误;适应性维护,即修改软件以适应环境的变化。完善性维护,即根据用户的要求改进或扩充软件使它更完善;预防性维护,即修改软件为将来的维护活动预先做准备。
五个生命周期模型过程模型
瀑布模型:
- 历史悠久、广为人知,优势在于它是规范的、文档驱动的方法,
- (1)阶段间具有顺序性和依赖性;(2)推迟实现的特点【清楚地区分逻辑设计与物理设计,尽可能推迟程序的物理实现{重要指导思想}】;(3)质量保证的观点【每个阶段必须完成规定的文档】
- 问题是,最终交付的产品可能不是用户真正需要的。
快速原型模型(克服瀑布模型缺点提出)
快速、容易修改
快速构建一个可运行的原型模型,让用户试用原型并收集用户反馈意见的办法,获取用户的真实需求(一旦需求确定,原型将被抛弃)[妥妥的渣男啊]
它所能完成的功能往往是最终产品完成功能的一个子集。
尽可能快:加速软件开发过程,节约软件开发成本。
增量模型:(渐增模型)
把软件产品作为一系列的增量构件来设计、编码、继承和测试.每个构件由多个相互作用的模块构成,并且完成特定的功能。第一个增量构件往往实现软件的基本需求,并且完成特定功能;
优点:在软件开发的早期阶段使投资获得明显回报和易于维护
但是,要求软件具有开放结构是使用这种模型时固有的困难。
风险驱动的螺旋模型:(适用大规模的内部开发项目)
理解:看作在每个阶段之前都增加了风险分析过程的快速原型模型
但是,只有在开发人员具有风险分析和排除风险的经验及专门知识时,使用这种模型才会获得成功。
喷泉模型:(典型的适合==面向对象范型==的过程模型)
当使用面向对象范型开发软件时,软件生命周期必须是循环的,也就是说,软件过程必须支持反馈和迭代。
需求分析
传统的软件工程方法学采用==结构化分析==完成需求分析工作;需求分析是发现、求精、建模、规格说明和复审的过程。
结构化分析就是建立模型的活动,数据模型,功能模型,行为模型
模型,既是软件设计的基础,也是编写软件需求规格说明书的基础。
通过需求分析建立的模型必须达到三个基本目标:
·描述用户的需求。
·为软件设计工作奠定基础。
·定义一组需求,一旦开发出软件产品之后,就可以用这组需求为标准来验收该产品。
访谈(会谈):最早开始的获取用户需求的技术,至今仍然广泛使用的主要需求分析技术。
正式的:系统分析员提出事先准备好的问题;
非正式的:提出些自由回答的开放性问题。
分发调查表:当需要调查大量人员意见时;
访谈过程中使用情景分析技术,[对用户运用目标系统解决某个具体问题的方法和结果进行分析]
简易应用规格说明技术,遵循的基本准则;为了促使用户与分析员密切合作共同分析需求,人们研究出一种面向团队的需求收集法,现在,这种技术已经成为信息系统界使用的主流技术。
实践表明,快速建立软件原型是最准确、最有效和最强大的需求分析技术。快速原型应该具备的基本特性是**“快速”和“容易修改”**,因此,必须有适当的软件工具支持快速原型技术。
结构化分析过程中导出的分析模型结构
![]()
1. 实体-关系图(E-R图)
数据模型包含三种相互关联的信息:
数据对象
描述数据对象的属性;
数据对象彼此间相互连接的关系(联系)[联系也可能有属性]
- 一对一联系:(1:1)
- 一对多联系:(1:N)
- 多对多联系:(M:N)
实体(数据对象)::japanese_goblin: ==矩形框==表示
关系:==菱形框==表示(连接相关实体)
属性:==椭圆形或圆角矩形==表示实体(或关系)的属性
无向边把实体、关系、属性连接起来。
我觉得吧,最好在主码下面加下划线。
2. 数据流图(DFD)
描述信息流和数据从输入移动到输出的过程中经受的变换。
四种基本符号:
- 正方形表示数据的源点或终点;
- 圆角矩形(或圆形)代表变换数据的处理;
- 开口矩形(或两条平行线)代表数据存储;
- 箭头表示数据流(特定数据的流动方向)。
==步骤==:
- 从问题描述中提取数据流图的四种成分;
- 接下来考虑处理;
- 最后,考虑数据流和数据存储。
例子:
- 组成数据流图的元素可以从描述的信息中提取出来
上面加星号标记的是在问题描述中隐含的成分。
任何系统的基本模型由若干个数据源点/终点以及一个处理组成。处理代表系统对数据加工变换的基本功能。下面画出基本系统模型,很有价值的通信工具:
进一步细化描述系统的主要功能,给处理和数据存储都加编号(便于引用和追踪):
主要功能进一步细化,必须保持信息连续性[当把一个处理分解为一系列处理时,分解前后的输入/输出数据流必须相同]
数据流图各项命名:(起名字困难:数据流图分解不恰当; 重新分解)
- 数据流:代表整个数据流
- 处理:反应整个处理的功能(一个具体的及物动词加宾语)
3. 状态转换图()
建立目标系统的行为模型,描绘系统的状态及引起系统状态转换的事件来表示系统的行为。
状态:任何可以被观察到的系统行为模式。
状态规定了系统对事件的响应;一个(一系列)动作;仅仅改变系统本身状态;
既改变状态又做动作。
主要有:初态、终态和中间状态。一个状态图中只能有一个初态,终态0至多个。
事件:特定时刻发生的事情;引起系统状态转换的控制信息;
==符号==:
初态用实心圆表示;终态用同心圆表示;
中间状态用圆角矩形表示,【可分为上、中、下3个部分,上面为状态名称(必须);中间为状态变量的名字和值(可选);下面是活动表(可选).
活动表的语法格式:事件名(参数表) / 动作表达式” 事件名“可以是是任何事件的名称;经常使用三种:entry、exit和do,
entry事件指定进入该状态的动作;do事件指定该状态下的动作;
动作表达式描述应做的具体动作。是一个过程表达式,状态转换开始时执行。
事件表达式语法:事件说明 [守卫条件] / 动作表达式
事件说明语法:事件名(参数表)。
事件说明和守卫条件为 ==与==
0. 数据字典
系统中使用的所有数据元素的定义的集合。
= 意思是等价于(或定义为);+意思是和(连接两个分量);
[ ] 意思是或 (列出的若干分量中选择一个,用” | “ 隔开);
{ } 意思是 重复(重复花括号内的分量)
( ) 意思是可选 (圆括号里的分量可有可无)
“…” 基本数据元素 x=”a” ; .. 连结符 x=1..9
数据流图与数据字典配合
清楚地表达数据处理的要求。
词条描述:对数据流图中每一个被命名的图形元素,加以定义;内容有:名字、别名或编号,分类,描述,定义,位置,其它,等
![]()
![]()
![]()
![]()
![]()
基本加工逻辑说明
每一个基本加工都有;
描述基本加工如何把输入数据流变换为输出数据流的加工规则;
描述加工策略,而不是实现加工细节;
包含的信息应是充足的,完备的,有用的,没有重复的多余信息。
1. 结构化英语
词汇表(英语命令动词、数据词典中定义的名字、有限的自定义词,逻辑关系词等)
2.判定表
数据流图的加工依赖于多个逻辑条件的取值
3. 判定树
有时候比判定表更直观。
结构化分析实例
1.问题陈述
2.问题定义
3.可行性研究
抽象和简化系统分析和设计的全过程:用最小代价尽快确定问题是否能被解决。
8个步骤:
- 澄清系统规模和目标;
- 研究现有程序;
- 导出高层逻辑模型;
- 进一步确定系统规模和目标;
- 导出供选择的解法;
- 推荐最佳方案;
- 草拟开发计划;
- 写出文档提交审查。
4.需求分析
沿数据流图回溯:
为了把数据流和数据存储定义到元素级别,从数据流图输出端着手;输出端的数据元素决定了系统基本构成。
写出文档初稿:一致的、容易理解的
完成的正式文档(==软件需求规格说明书==)必须至少包含三个重要成分:
- 数据流图
- 数据字典
- 一组黑盒形式的算法描述
定义逻辑系统
细化数据流图
书写正式文档
技术审查和管理复审
结构化设计
1.构化设计与结构化分析的关系
概要设计:
仔细分析软件规格说明,适当进行功能分解,把软件划分为模块,设计出完成预定功能的模块结构
详细设计:
详细的设计每个模块,确定完成每个模块功能所需要的算法和数据结构
由数据模型、功能模型和行为模型清楚地表示软件需求;
软件设计者使用适当的设计方法完成:数据设计、体系结构设计、接口设计和过程设计。
2.软件设计的概念和原理
- 模块化:
模块 “组件”
过程、函数、子程序和宏等都可作为模块。
面向对象范型中的对象,对象内的方法也是模块
模块可分解性;
模块可组装性;
模块可理解性;
模块连续性;
模块保护性
抽象
逐步求精:
为了能集中精力解决主要问题而尽量推迟对问题细节的考虑,实际上是细化过程
抽象与求精是一对互补的概念。
信息隐藏:
使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,不能访问。
3.模块独立
是模块化、抽象、逐步求精和信息隐藏等概念的直接结果;
也是完成有效模块设计的基本标准。
==内聚和耦合==
耦合:
不同模块彼此间相互依赖的紧密程度;
内聚:
一个模块内部各个元素彼此结合的紧密程度。
内聚与耦合
耦合 :
尽量使用数据耦合,少用控制耦合,限制公共环境耦合的范围,完全不用内容耦合。

- 非直接耦合(Nondirect Coupling)
如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的,这就是非直接耦合。这种耦合的模块独立性最强。
数据耦合 (Data Coupling)
如果一个模块访问另一个模块时,彼此之间是通过数据参数 (不是控制参数、公共数据结构或外部变量) 来交换输入、输出信息的,则称这种耦合为数据耦合。标记耦合 (Stamp Coupling)
如果一组模块通过参数表传递记录信息,就是标记耦合。这个记录是某一数据结构的子结构,而不是简单变量。控制耦合 (Control Coupling)
如果一个模块通过传送开关、标志、名字等控制信息, 明显地控制选择另一模块的功能,就是控制耦合。
外部耦合(External Coupling)
一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。公共耦合(Common Coupling)
若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。公共耦合的复杂程度随耦合模块的个数增加而显著增加。若只是两模块间有公共数据环境,则公共耦合有两种情况。松散公共耦合和紧密公共耦合内容耦合 (Content Coupling)
如果发生下列情形,两个模块之间就发生了内容耦合
(1) 一个模块直接访问另一个模块的内部数据;
(2) 一个模块不通过正常入口转到另一模块内部;
(3) 两个模块有一部分程序代码重迭(只可能出现在汇 编语言中);
(4) 一个模块有多个入口。
内聚

- 功能内聚 (Functional Cohesion)
一个模块中各个部分都是完成某一具体功能必不可少的组成部分,或者说该模块中所有部分都是为了完成一项具体功能而协同工作,紧密联系,不可分割的。则称该模块为功能内聚模块。
- 信息内聚 (Informational Cohesion)
这种模块完成多个功能,各个功能都在同一数据结构上操作,每一项功能有一个唯一的入口点。这个模块将根据不同的要求,确定该执行哪一个功能。由于这个模块的所有功能都是基于同一个数据结构(符号表),因此,它是一个信息内聚的模块。信息内聚模块可以看成是多个功能内聚模块的组合,并且达到信息的隐蔽。即把某个数据结构、资源或设备隐蔽在一个模块内,不为别的模块所知晓。
通信内聚 (Communication Cohesion)
如果一个模块内各功能部分都使用了相同的输入数据,或产生了相同的输出数据,则称之为通信内聚模块。通常,通信内聚模块是通过数据流图来定义的。过程内聚(Procedural Cohesion)
使用流程图做为工具设计程序时,把流程图中的某一部分划出组成模块,就得到过程内聚模块。例如,把流程图中的循环部分、判定部分、计算部分分成三个模块,这三个模块都是过程内聚模块。
时间内聚(Classical Cohesion)
时间内聚又称为经典内聚。这种模块大多为多功能模块,但模块的各个功能的执行与时间有关,通常要求所有功能必须在同一时间段内执行。例如初始化模块和终止模块。
逻辑内聚(Logical Cohesion)
这种模块把几种相关的功能组合在一起,每次被调用时,由传送给模块的判定参数来确定该模块应执行哪一种功能。
- 巧合内聚(Coincidental Cohesion)
巧合内聚又称为偶然内聚。当模块内各部分之间没有联系,或者即使有联系,这种联系也很松散,则称这种模块为巧合内聚模块,它是内聚程度最低的模块。缺点:模块的内容不易理解、不易修改和维护。
4启发规则
改进软件结构提高模块独立性
模块规模应该适中
深度、宽度、扇出和扇入都应适当
模块的作用域应该在控制域之内
力争降低模块接口的复杂程度
设计单入口单出口的模块
模块功能应该可以预测
5.表示软件结构的图形工具
一、层次图和HIPO图
- 层次图
在层次图中一个矩形代表一个模块;
框间连线表示调用关系;(上方的调用下方的)
HIPO图 [层次图+输入+处理+输出]
为了具有可跟踪性:在H图里除顶层方框外,每个方框都加了编号。

二、结构图
和层次图类似
一个方框代表一个模块【框内注明模块的名字或主要功能】
方框间的箭头表示模块的调用关系。
还用带注释的箭头表示调用过程中来回传递的信息
尾部是空心圆传递的是数据;
实心圆表示传递的是控制信息;
6.面向数据流的设计方法
任何软件系统都可以用数据流图表示;所以理论上面向数据流的设计方法理论上可以设计任何软件结构。
通常所说的结构化设计就是基于数据流的设计
信息流的类型决定映射的方法(两种类型)
事务流和交换流
变换流:有变换中心,输入流和输出流不同
事务流:有事务中心,没有加工变换,事务不变

7.人机界面设计
总会遇到下述四个问题:
系统响应时间、用户帮助设施、出错信息处理和命令交互。系统响应时间有两个重要属性,分别是长度和易变性。
常见的帮助设施有集成的和附加的两类。
8.过程设计
在数据设计、体系结构设计和接口设计完成之后进行,它是详细设计阶段应该完成的主要任务。
结构程序设计的经典定义: 如果一个程序的代码块仅仅通过顺序、选择和循环这三种控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的。
上述定义过于狭隘:结构程序设计本质上是一种使程序代码容易阅读、容易理解的编程方法。但,(当出现错误条件时,重要的是在数据库奔溃或栈溢出之前尽可能快地从当前程序退到一个出错处理程序)最好方法是使用Go To语句
【不可滥用GOTO语句】
9.过程设计的工具
分为图形、表格和语言三类
一、程序流程图
又称为程序框图,它是历史最悠久使用最广泛的描述过程设计的方法,然而它也是用得最混乱的一种方法。

二、.盒图(N-S图)

三、 PAD图
问题分析图
二维树形结构的图来表示程序的控制流,
容易翻译成程序代码

四、判定表
当算法中包含多重嵌套的条件选择时,用程序流程图、盒图、PAD图、或过程设计语言(PDL)都不易清楚地描述。
一张判定表由四部分组成,
左上部列出所有条件,
左下部是所有可能做的动作,
右上部是表示各种条件组合的一个矩阵,
右下部是和每种条件组合相对应的动作。
五、判定树
是判定表的变种,也能清晰地表达复杂的条件组合与应做的动作之间的对应关系。
六、过程设计语言(PDL)
PDL也称伪码,用正文形式表示数据和处理过程的设计工具
有严格的关键字外部语法,用于定义控制结构和数据结构;
表示实际操作和条件的内部语法通常又是灵活自由的,以适应各种工程项目的需要。
10.面向数据结构的设计方法
适合于在详细设计阶段使用,在完成软件结构设计后
可使用面向数据结构的方法来设计每个模块的处理过程。
逻辑结构也只有三类:顺序、选择、重复
Jackson图

下面结合一个具体例子进一步说明Jackson结构程序设计方法。
[例]一个正文文件由若干个记录组成,每个记录是一个字符串。要求统计每个记录中空格字符的个数,以及文件中空格字符的总个数。要求的输出数据格式是,每复制一行输入字符串之后,另起一行印出这个字符串中的空格数,最后印出文件中空格的总个数。
结构化实现 (实现=编码+测试)
经验表明,审查不能发现所有差错;编码过程中不可避免的引入新的错误。
软件测试的两个阶段:
单元测试:编写出每个模块之后
编写者和测试者是同一个人;
编码和单元测试属于同一阶段
各种综合测试:另一独立阶段
专门测试人员
测试目标:发现软件的错误;
软件工程根本目标:开发出高质量的完全符合用户需要的软件,因此,通过测试发现错误之后还必须诊断并改正错误,这就是调试的目的。
程序语言的特征包括:算法特性
软件实现是将软件设计(不是详细设计)的结果翻译成程序代码
成功测试指运行测试用例后发现了程序错误,而不是证明程序正确
软件测试的目的:尽可能多地发现错误,而不是证明软件的正确性
验收测试的任务:验证软件的有效性,不是正确性
编码
1.选择程序设计语言
- 使用汇编语言的场景(很少用,其他大多场景都用高级语言)
对程序执行时间和使用的空间有严格限制
需要产生任意的甚至非法的指令序列
不能实现高级语言编译程序的微处理机
大型系统中执行时间非常关键的一小部分代码
直接依赖于硬件的一小部分代码
- 选用高级语言的要求
①有理想的模块化机制、可读性好的控制结构和数据结构
目的:容易测试和维护,减少生命周期的总成本
②使编译程序可以尽可能多地发现程序中的错误
目的:便于调试、提高软件可靠性
③有良好的独立编译机制
目的:降低开发和维护的成本
④不仅考虑理论的标准,还要考虑使用方面的限制
2.编码风格
程序内部的文档
恰当的标识符、适当的注解、程序的视觉组织等
数据说明
语句构造
每个语句应简单而直接,不能为了提高效率而使程序变得过分复杂。
- 一行一语句;
- 尽量避免负责的条件测试;
- 尽量避免非条件;
- 避免嵌套;
- 利用括号表明运算次序。
输入/输出
对所有输入数据都进行检验;
检查输入项重要组合的合法性;
保持输入格式简单;
使用数据结束标记,不要要求用户指定数据的数目;
明确提示交互式输入的请求,详细说明可用的选择或边界数值;
当程序设计语言对格式有严格要求时,应保持输入格式一致;
设计良好的输出报表;
给所有输出数据加标志。
效率
主要两方面:处理机事件和存储器容量
- 效率是性能要求,因此应该在需求分析阶段确定效率方面的要求。软件应该像对它要求的那样有效,而不应该如同人类可能做到的那样有效。
- 效率是靠好设计来提高的。
- 程序的效率和程序的简单程度是一致的。不要牺牲程序的清晰性和可读性来不必要地提高效率。
软件测试基础
1.测试目标
测试是为了发现程序中的错误而执行程序的过程;
好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案;
成功的测试是发现了至今为止尚未发现的错误的测试。
在综合测试阶段由测试小组完成
2.黑盒测试和白盒测试
黑盒测试:
在程序接口进行的测试,它只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据产生正确的输出信息,并且保持外部信息 (如,数据库或文件) 的完整性。黑盒测试又称为功能测试、数据驱动测试。
白盒测试:
按照程序内部的逻辑测试程序,检验程序中的每条通路是否都能按预定要求正确工作。白盒测试又称为结构测试、逻辑驱动测试。
3.测试准则
4.流图
为了突出表示==程序的控制流==,可以使用流图也称为程序图
仅描绘程序的控制流程,它完全不表现对数据的具体操作以及分支或循环的具体条件。
圆表示节点,一个圆代表一条或多条语句
程序流程图中的一个处理框序列和一个菱形判定框,可以映射成流图中的一个节点。
流图中的箭头线称为边,它和程序流程图中的箭头线类似,代表控制流。
流图中一条边必须终止于一个节点,即使这个节点并不代表任何语句(相当于一个空语句
由边和节点围成的面积称为区域,当计算区域数时应该包括图外部未被围起来的那个区域。

- 由PDL翻译成流图
逻辑覆盖(白盒)
设计白盒测试方案中的一种技术
设计测试方案是测试阶段的关键技术问题;
测试方案:具体的测试目的(如,要测试的功能),应该输入的测试数据,和预期的输出结果。
把测试数据和预期的输出结果成为==测试用例==
选用少量“最有效”的测试数据,做到尽可能完备的测试。
语句覆盖:
选择足够多的测试数据,使被测程序中的每个语句至少执行一次
判定覆盖(分支覆盖):
不仅每个语句必须至少执行一次,而且每个判定的每种可能结果都应该至少执行一次;
条件覆盖:
不仅每个语句至少执行一次,而且使判定表达式中每个条件都取到各种可能的结果。
判定/条件覆盖:
同时满足两种覆盖标准的覆盖逻辑
控制结构测试
基本路径测试(白盒)
步骤:
根据过程设计结果画出相应的流图;
计算流图的环形复杂度;
- 流图中的区域数等于环形复杂度
- 流图G的环形复杂度V(G)=E-N+2,其中E是流图中边的条数,N是流图中节点数。
- 环形复杂度V(G)=P+1,其中P是流图中判定节点的数目。
![]()
通过上面三种方法,都可得出环形复杂度为6.
确定线性独立路径的基本集合
==独立路径==,至少引入程序的一个新处理语句集合或一个新条件的路径。(至少包含一条在定义该路径之前不曾用过的边。)
环形复杂度决定程序中独立路径的数量。是确保程序中所有语句至少被执行一次所需的测试数量的上界。
判定节点:2、3、5、6、10.(上图)
设计可强制执行基本集合中每条路径的测试用例。
条件测试(白盒)
能检查出程序模块中包含的逻辑条件。
一个简单条件是一个布尔变量或一个关系表达式
数据流测试
根据程序中变量定义和使用位置,选择程序的测试路径。
循环测试(白盒)
专注于测试循环结构的有效性
三种循环:简单循环、串接循环、嵌套循环
简单循环
嵌套循环
串接循环
==黑盒测试技术==
着重测试软件的功能需求;
与白盒测试互补;
白盒测试在测试过程的早期阶段进行;黑盒测试主要用于测试过程的后期。故意不考虑程序的控制结构,集中于信息域。
1.等价划分
划分输入数据的等价类,需要研究程序的功能说明,从而确定输入数据的有效等价类和无效等价类。
常常根据输出数据的等价类导出对应的输入数据等价类。
==一些规则==:
等价类测试方案:
每个测试方案由三部分组成:
- 描述、输入、预期输出
等价类划分:等价类划分举例
2.边界值分析
处理边界情况时程序最容易发生错误;
例如,下标、纯量、数据结构和循环等边界附近。
测试方案首先应该确定边界情况,通常输入等价类和输出等价类的边界就是。
测试数据应刚好等于、刚刚小于、刚刚大于
3.错误推测
很大程度上靠直觉和经验进行
列出程序中可能有的错误和容易发生错误的特殊情况。
测试策略
- 测试步骤
顺序进行的四个步骤:
单元测试(大量使用白盒测试技术)
检查模块控制结构中的特定路径
集成测试(同时解决程序验证和程序构造俩问题)
常用黑盒测试用例技术(也可使用定量的白盒测试)
继承后进行一系列高级测试;
必须测试(需求分析阶段确定下来的确认标准)
对软件满足所有功能的、行为的和性能的需求的最终保证(仅仅使用黑盒测试)
- 单元测试
代码审查
属于人工测试程序,由–审查小组–进行
- 组长,很有能力的,没有直接参与这项工程;
- 程序的设计者;
- 程序的编写者;
- 程序的测试者。
人工测试与计算机测试相互补充,相辅相成。
测试软件

、
- 集成测试
发现与接口有关的问题;
- 自顶向下集成
- 自底向上集成
- 回归测试
- 不同测试策略的比较
- 确认测试
- 确认测试的范围
- 软件配置复查
- Alpha和Beta测试
调试
测试发现错误后排除错误的过程
调试过程
试图找出产生症状的原因
调试途径
- 蛮干法;
- 回溯法;
- 原因排除法。
软件可靠性
定义:程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。
软件可用性:程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。
T
down:系统故障时间 ; Tup: 正常运行时间系统稳态可用性:A
ss= $\frac{Tup}{Tup+Tdown}$MTTF :系统平均无故障时间 ; MTTR平均维修时间
A
ss= $\frac{MTTF}{MTTF+MTTR}$
估算平均无故障时间
ET——测试之前程序中错误总数;
IT——程序长度(机器指令总数);
τ——测试(包括调试)时间;
Ed(τ)——在0至τ期间发现的错误数;
Ec(τ)——在0至τ期间改正的错误数。
平均无故障时间与单位长度程序中剩余的错误数成反比;(K=200)
MTTF=$\frac{1}{K(E_T/I_T - E_c(\tau)/I_T)}$
E
c= ET- $\frac{I_T}{K \times MTTF}$估计错误总数的方法
- 植入错误法
- 分别测试法
面向对象方法学
只有类的共有界面的成员能操作类,这是软件设计的信息隐藏原则(不是共享性原则)
面向对象设计中,对象信息的隐藏主要通过对象的封装性实现(不是通过系统模块化)
面向对象设计的主要任务:系统设计、对象设计
对象/模块:把数据结构和操作这些数据的方法紧密地结合在一起
1.面向对象的优点
①与人类习惯的思维方法一致
②稳定性好(功能需求变化时并不会引起软件结构的整体变化)
③可重用性好(通过创建类的实例直接使用,或派生出满足需要的新类)
④较易开发大型软件产品(可分成若干小产品来开发)
⑤可维护性好(←稳定性好、易修改、易理解、易测试、易调试)
2. 面向对象概念
- 对象
对象是具有相同状态的一组操作的集合(面向对象程序设计角度)
是对问题域中某个东西的抽象,即对象是对属性值和操作的封装(信息模拟角度)
形式化定义对象∷=<ID,MS,DS,MI>
ID是对象的标识或名字,MS是对象中的操作集合
DS是对象的数据结构,MI是对象受理的消息名集合(即对外接口)
对象可以是物理实体的抽象、认为的概念、任何有明确边界和意义的东西
对象是面向对象程序的 基本模块/核心
==特点==:以数据为中心,主动,实现了数据封装,本质上具有并行性,模块独立性好
- 类
类是对具有相同属性和行为的一个或多个对象的描述
通常在这种描述中也包括对怎样创建该类的新对象的说明
定义属性:数据类型、数据结构、访问权限
定义服务:设计完成每项服务功能的算法
- 迭代
对象类:软件IC
- 消息
消息是要求某个对象执行在定义它的那个类中所定义的某个操作的规格说明
组成
接收消息的对象
消息选择符/消息名
零个或多个变元
实例:由某个特定的类所描述的一个具体的对象
方法:对象所能执行的操作,即类中所定义的服务。
属性:类中所定义的数据,是对客观世界实体所具有的性质的抽象
封装:把某个事物包起来,使外界不知道该事物的具体内容
- 具有封装性的条件
有一个清晰的边界(使私有数据和实现操作的代码对外部屏蔽)
有确定的接口,即协议
受保护的内部实现
继承:能直接获得已有的性质和特征,而不必重复定义它们。分为单继承和多重继承
多态性
子类对象可以像父类对象那样使用
同样的消息既可以发送给父类对象也可以发送给子类对象
重载
函数重载:同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字
运算符重载:同一个运算符可以施加于不同类型的操作数上面
3. 面向对象的三个子模型、五个层次以及四个子系统
- 三个子模型
- 对象模型(类图):描述系统数据结构【做事情的实体】【静态结构】
- 动态模型(状态图):描述系统控制结构 【什么时候做】【交互层次】
- 功能模型(用例图):描述系统功能 (一组数据流图) 【做什么】【数据交换】
对象模型是最基本、最核心、最重要的。
- 五个层次
每一层从不同角度将对象模型更细化、更具体化
面向对象分析:寻找类与对象,识别结构,定义属性,建立动态模型,建立功能模型,定义服务。
- 主题层(范畴层)
- 类–对象层
- 结构层
- 属性层
- 服务层
- 四个子系统
子系统之间交互的两种方式:
- 客户-供应商关系
- 平等伙伴关系
组织子系统的两种方案:
- 水平层次组织
- 垂直块组织
子系统组成完整系统的典型拓扑结构:管道型、树型、星型等
尽可能简单的拓扑结构,以减少子系统间的交互数量。
- 问题域子系统;
- 人机交互子系统
- 任务管理子系统
- 数据管理子系统
设计问题域子系统
- 调整需求;
- 重用已有类;
- 把问题域类组合在一起;
- 增添一般化类以建立协议
设计人机交互子系统
- 设计人机交互准则:
- 一致性
- 减少步骤
- 及时提供反馈信息
- 提供撤销命令
- 无须记忆
- 易学
- 富有吸引力
- 设计人机交互子系统的策略
- 分类用户
- 描述用户
- 设计命令层次
- 研究现有的人机交互含义和准则
- 确定初始的命令层次
- 精华命令层次
- 设计人机交互类
- 设计人机交互准则:
设计任务管理子系统
- 分析并发性;
- 设计任务管理子系统
- 确定时间驱动型任务
- 确定时钟驱动型任务
- 确定优先任务
- 确定关键任务
- 确定协调任务
- 尽量减少任务数
- 确定资源需求
设计数据管理子系统
- 选择数据存储管理模式
- 文件管理系统
- 关系数据库管理系统
- 面向对象数据库管理系统
- 设计数据管理子系统
- 设计数据格式
- 设计相应任务
- 选择数据存储管理模式
设计类中服务
确定类中应有服务

设计设计实现服务的方法
设计实现服务的算法
- 算法复杂度
- 容易理解与容易实现
- 容易修改
选择数据结构

定义内部类和内部操作
设计关联
- 关联的遍历
- 实现单向关联
- 实现双向关联
- 关联对象的实现方法
设计优化
- 确定优先级
- 提高效率的几项技术
- 增加冗余关联以提高访问效率
- 调整查询次序
- 保留派生属性
- 调整继承关系
- 抽象与具体
- 为提高继承程度而修改类定义
- 利用委托实现行为共享
4.需求陈述
描述用户的需求而不是提出解决问题的方法。
5.建立对象模型
建立对象模型的主要信息来源
需求陈述
应用领域的专业知识
关于客观世界的常识
建立对象模型步骤
①确定类与对象
②确定关联
③划分主题
④确定属性
⑤识别继承关系
⑥反复修改
筛选类域对象的主要标准
冗余、无关、笼统、属性、操作、实现
筛选关联的主要标准
应该删除的五种
①已删去的类之间的关联
②与问题无关的或应在实现阶段考虑的关联
③瞬时事件
④三元关联
⑤派生关联
应该完善的四方面
①正名
②分解
③补充
④标明重数
确定属性的两过程
分析
定义:提取系统需求并建立问题域精确模型的过程
主要工作内容:理解、表达、验证
关键工作:分析、确定问题域中对象及对象间的关系,并建立起问题域的对象模型
选择
删除不正确的或不必要的属性
(1) 误把对象当作属性(如果某个实体的独立存在比它的值更重要,则应把它作为一个对象而不是对象的属性)
(2) 误把关联类的属性当作一般对象的属性
(3) 把限定误当成属性
(4) 误把内部状态当成了过于细化属性
(5) 过于细化
(6) 存在不一致的属性
存在看起来与其他属性毫不相关的属性,应该把该类分解成两个不同的类
建立继承/泛化关系的两种方式
自底向上
抽象出现有类的共同性质泛化出父类
这个过程模拟了人类归纳思维过程
自顶向下
把现有类细化成更具体的子类
这个过程模拟了人类的演绎思维过程
6.建立动态模型
步骤:
- 编写典型交互行为的脚本
- 从脚本中提取出事件,确定触发每个事件的动作对象以及接受事件的目标对象
- 排列事件发生次序,确定每个对象可能的状态及状态间的转换关系,并用状态图描绘
- 比较各个对象的状态图,检查它们之间的一致性,确保事件之间的匹配
事件跟踪图实质上是扩充的脚本,而且可以把它看作是简化的UML顺序图
7.建立功能模型
8.定义服务
面向对象设计
准则(弱耦合、强内聚)
2个耦合:
交互耦合:对象之间的耦合通过消息连接来实现
为使交互耦合松散应该遵守的准则
①尽量降低消息连接的复杂程度
②减少对象发送(或接收)的消息数
继承耦合(越高越好)
为获得紧密的继承耦合,特殊类应该确实是对它的一般化类的一种具体化
3个内聚
- 服务内聚:一个服务应该完成一个且仅完成一个功能
- 类内聚:一个类应该只有一个用途,它的属性和服务应该是高内聚的
- 一般-特殊内聚:应该符合多数人的概念,应该是对相应的领域知识的正确抽取
启发规则
设计结果应该清晰易懂
用词一致
使用已有的协议
减少消息模式的数目
避免模糊的定义
一般—特殊结构的深度应适当
设计简单的类
避免包含过多的属性
有明确的定义
尽量简化对象之间的合作关系
不要提供太多服务
使用简单的协议
使用简单的服务
把设计变动减至最小
面向对象的实现
面向对象测试用例的设计:设计适当操作序列以检查类的状态
传统测试用例设计:由软件的输入-处理-输出视图或单个模块的算法细节驱动
- 面向对象语言的优点
- 一致的表示方式
- 可重用性
- 可维护性
- 技术特点
- 支持类与对象概念的机制
- 实现整体—部分结构的机制
- 实现一般—特殊结构的机制
- 实现属性和服务的机制
- 类型检查
- 类库
- 效率
- 持久保存对象
- 参数化类
- 开发环境
- 考虑的因素
- 将来能否占主导地位
- 可重用性
- 类库和开发环境
- 其他因素
-程序设计风格
提高可重用性(编码阶段主要考虑代码重用)
实现重用的设计准则
①提高方法的内聚
②减小方法的规模
③保持方法的一致性
④把策略与实现分开
⑤全面覆盖
⑥尽量不使用全局信息
⑦利用继承机制(实现共享和提高重用程度的主要途径)
(1) 调用子过程
(2) 分解因子
(3) 使用委托
(4) 把代码封装在类中
提高可扩充性
提高可扩充性的准则
①封装实现策略
②不要用一个方法遍历多条关联链
③避免使用多分支语句
④精心确定公有方法
- 提高健壮性
提高健壮性的准则
①预防用户的操作错误
②检查参数的合法性
③不要预先确定限制条件
④先测试后优化
测试策略
从小到大,单元测试→集成测试→确认测试和系统测试
单元测试(把操作作为类的一部分来测试,不再是逻辑覆盖)
集成测试
①基于线程的测试
把响应系统的一个输入或一个事件所需要的一组类集成起来
分别集成并测试每个线程,同时应用回归测试以保证没有产生副作用
(简述:集成一组相互协作以对某个输入或某个事件作出响应的类)
②基于使用的测试
首先测试几乎不使用服务器类的那些类(称为独立类)
接下来测试使用独立类的下一个层次的类(称为依赖类)
对依赖类逐层测试,直至把整个软件系统构造完为止
(简述:从那些不使用服务器类的类开始,按层次构造系统)
集群测试是集成测试的一个步骤
确认测试
和传统的确认测试一样,集中检查用户可见的动作和用户可识别的输出
面向对象系统的确认测试也是面向黑盒的
面向对象设计确认测试用例
以动态模型和描述系统行为的脚本为主,以传统黑盒测试为辅
(以基于情景的测试为主)
设计测试用例
测试单个类的方法
随机测试
划分测试:可减少测试类时所需要的测试用例的数量,与传统的等价划分类似
划分类别的方法
基于状态的划分
基于属性的划分
基于故障的测试:推测可能的错误后设计测试用例,与传统的错误推测法类似
集成测试方法
也可用随机测试法、划分测试法
(统一建模语言)UML
UML1:https://adtxl.com/index.php/archives/84.html
UML2https://www.jianshu.com/p/c602650e50d1

FAQ
状态图、顺序图、协作图、活动图区别?
- 状态图描述一个特定对象的所有可能的状态以及引起状态转换的事件;
- 顺序图描述对象之间的动态交互关系,着重表现对象间消息传递的时间顺序;
- 协作图描述相互协作的对象间交互关系和链接关系,着重表现交互对象的静态链接关系;
- 活动图是状态图的变种,主要描述动作及动作的结果——对象状态的改变。
结构化分析工具:实体-关系图(E-R图)、数据流图、状态转换图、数据字典
过程设计工具分别适合什么场景?
程序流程图又称程序框图,一直是过程设计的主要工具
盒图(N-S图),详细设计的工具;
PAD图是问题分析图,是面向高级程序设计语言的;
判定表:当算法中包含多重嵌套的条件选择时,使用判定表能够清晰的表示复杂的条件组合与应做的动作之间的对应关系;
判定树是判定表的变种,形式简单,当数据元素的值多于两个时,用判定树。
类与类之间的4中关系:
- 关联、泛化、依赖、细化
对象的特点:
- ①以数据为中心
- ②实现了数据封装
- ③本质上具有并行性
- ④模块独立性好
建立对象模型的步骤
- (1)确定类与对象
- (2)确定关联
- (3)划分主题
- 4)确定属性
- (5)识别继承关系
- (6)反复修改
建立动态模型步骤
- 1)编写脚本
- (2)设想用户界面
- (3)画事件跟踪图
- (4)画状态图(
- 5)审查动态模型
- UML的9种图
- 用例图
- 静态图:类图、对象图
- 行为图:状态图、活动图
- 交互图:顺序图、协作图
- 实现图:构件图、部署图





































