软件工程
软件工程
一门指导计算机软件开发和维护的工程学科
一、软件生命周期
由三个时期组成:软件定义、软件开发、运行维护(软件维护)
- 软件定义时期:问题定义、可行性研究、需求分析
- 问题定义:要解决的问题是什么?
- 可行性研究:对于上一阶段所确定的问题有行得通的解决办法吗?
- 需求分析:为了解决这个问题,目标系统必须做什么?
- 软件开发时期:系统设计(总体设计、详细设计)、系统实现(编码和单元测试、综合测试)
- 总体设计:概括地说,应该怎样实现目标系统?
- 详细设计:应该怎样具体地实现目标系统?
- 编码和单元测试:写出正确的容易理解、容易维护的程序模块,并测试编写的模块
- 综合测试:通过各种类型的测试使软件达到预定的要求(基本测试:集成测试和验收测试)
- 软件维护时期:软件维护
- 软件维护:通过各种必要的维护活动使系统持久地满足用户地需要
二、软件过程(开发模型)
为了获得高质量软件所需要完成地一系列任务地框架,规定完成各项任务地工作步骤
- who:目的 优质、高产
- when:时间
- what:做什么事
- how:怎样做
2.1 瀑布模型
20c80s之前,唯一被广泛采用地生命周期模型
now,依旧是应用最广泛地过程模型
2.1.1 传统的瀑布模型
特点:
- 阶段间具有顺序性和依赖性(前一阶段的输出文档为后一阶段的输入文档)
- 只有前一阶段正确,后一阶段才能获得正确的结果
- 推迟实现的观点(清楚地区分逻辑设计和物理设计,尽可能推迟程序的物理实现)
- 前面阶段不扎实,过早进行程序实现往往导致大量返工,浪费时间
- 质量保证的观点
- 每个阶段完成规定文档,及时审查,保证软件质量,降低软件成本
2.1.2 实际的瀑布模型
缺点:
瀑布模型由文档驱动,很可能不能真正满足用户的需求
适用场合:
适用于系统需求明确且稳定,技术成熟,工程管理严格的场合,如军工、航天、医疗。
2.2 快速原型模型
快速原型的本质是“快速”,原型的用途是获知用户的真实需求,一旦需求确定,原型将被抛弃,开发人员可以通过构建原型人后根据用户意见迅速地修改原型
优点:
- 减少需求不明确带来的风险
- 软件产品的开发基本上是线性进行的
缺点:
- 构造原型采用的技术和工具不一定主流.
- 快速建立起来的系统加上连续的修改可能导致原型质量低下
- 设计者在质量和原型中进行折中
- 客户意识不到一些质量问题
使用场合:
- 客户定义一个总体目标集,但是他们并不清楚系统的具体输入输出。
- 或开发者不确定算法的效率、软件与操作系统是否兼容以及客户与计算机交互的方式。
- 用户无系统使用经验,需求分析人员技能不足,尽量借助原型模型。
Unix shell和超文本都是广泛使用的快速原型语言
2.3 增量模型
- 将软件产品作为一系列的增量构件来设计、编码、集成和测试
- 每个构建由多个相互作用的模块构成,并且能够完成特定的功能(第一个增量构件往往实现软件的基本需求,提供最核心的功能)
- 此外,将软件产品分解为增量构件的时,应该使构件的规模适中,规模过大或过小都不好
- 分解时唯一必须遵守的约束条件是,当把新构件集成到现有软件中,所形成的产品必须是可测试的
优点:
- 能在较短时间内向用户提交可完成部分工作地产品
- 逐步增加产品功能可以使用户有比较充裕的时间学习和适应新产品,从而减少一个全新的软件可能给客户组织带来的冲击
缺点:
需要有效的管理和沟通,可能导致项目复杂性增加。
从某种意义上来讲,增量模型本身是自相矛盾的,一方面要求开发人员把软件看作一个整体,另一方面有要求开发人员把软件看作构件序列,每个构件本质上都独立于另一个构件。除非开发人员有足够的技术能力协调好这一明显的矛盾,否则增量模型开发出的产品可能并不令人满意
2.4 螺旋模型
软件开发中的风险:
- 交付的产品用户不满意.
- 产品不能按时交付.
- 开发成本超过预算.
- 产品开发期间关键开发人员离职.
- 产品投入市场前竞争对手发布功能相近价格更低产品
基本思想:
使用原型以及其他方法来尽量降低风险
优点:
- 螺旋模型强调原型的可扩充性和可修改性,原型的进化贯穿整个软件生存周期,这将有助于目标软件的适应能力,支持用户需求的动态变化;
- 原型可看作可执行的需求规格说明,易于为用户和开发人员共同理解,还可作为继续开发的基础,并为用户参与所有关键决策提供了方便;
- 螺旋模型为项目管理人员及时调整管理决策提供了方便,进而可降低开发风险。
- 减少了过多测试或测试不足所带来的风险。
- 对可选方案和约束条件的强调有利于已有软件的重用,也有助于把软件质量作为软件开发的一个重要目标。
缺点:
- 如果每次迭代的效率不高,致使迭代次数过多,将会增加成本并推迟交付时间
- 使用该模型需要有相当丰富的风险评估经验和专门知识,要求开发队伍水平较高,否则会带来更大风险,可能项目实际走向灾难时,开发人员还以为一切正常。
适用场合:
- 适用于需求不明确或者需求可能发生变化的大型复杂的软件系统。
- 支持面向过程、面向对象等多种软件开发方法,是一种具有广阔前景的模型。
- 适用于大规模内部开发项目,分析风险和排除风险
2.5 喷泉模型
迭代是软件开发过程中普遍存在的一种内在属性。经验表明,软件过程各个阶段之间的迭代或一个阶段内各个工作步骤之间的迭代,在面向对象范型中比在结构化范型中更常见。
喷泉模型,是典型的面向对象的软件过程模型之一,它与传统的瀑布模型和迭代模型不同,它不是将开发过程划分为阶段,而是认为软件开发是一个不断迭代的过程,每个迭代都包括多个不同的活动,例如需求分析、设计、编码、测试等等。
喷泉模型认为软件开发是一个不断迭代的过程,而不是将开发过程划分为阶段。每个迭代可以包括多个不同的活动,例如需求分析、设计、编码、测试等等。这意味着该模型具有很强的灵活性。
该模型中设计和编码是交织在一起的。设计可能会受到编码阶段中发现的问题的影响,并且编码阶段可能会引发设计的更改。这种交织的过程可以更好地解决需求不断变化的问题。
“喷泉”这个词体现了面向对象软件开发过程迭代和无缝的特性。图中代表不同阶段的圆圈相互重叠,这明确表示两个活动之间存在交迭;而面向对象方法在概念和表示方法上的一致性,保证了在各项开发活动之间的无缝过渡。
特点:
- 喷泉模型是一种以用户需求为动力,以对象为驱动的模型,主要用于描述面向对象的软件开发过程.
- 软件开发早期定义对象,整个开发过程充实和扩充对象.
- 为了避免使用喷泉模型开发软件时开发过程过分无序,应该把一个线性过程作为总目标。
- 各个阶段使用统一的概念和表示方法,生命周期各阶段无缝连接(面向对象方法在概念和表示方法上的一致性,保证了各项开发活动之间的无缝连接).
- 各个开发步骤多次反复迭代
- 传统软件过程模型
优点:
- 喷泉模型的各个阶段没有明显的界限,开发人员可以同步进行开发可以提高软件项目开发效率,节省开发时间适应于面向对象的软件开发过程
缺点:
- 由于喷泉模型在各个开发阶段是重叠的,在开发过程中需要大量的开发人员,因此不利于项目的管理
- 喷泉模型要求严格管理文档,使得审核的难度加大尤其是面对可能随时加入的各种信息、需求与资料的情况
适用场合:
面向对象开发(喷泉模型较好地体现了面向对象软件开发过程无缝迭代的特性,是典型的面向对象的软件过程模型之一)
三、软件测试
根本目的:尽可能多的发现并排除软件中潜藏的错误,最终把一个高质量的软件系统交给用户使用。
测试目标或定义:
- 测试是为了发现程序中的错误而执行程序的过程。
- 好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案。
- 成功的测试是发现了至今为止尚未发现的错误的测试。
测试准则:
- 所有测试都应该能追溯到用户需求。
- 应该远在测试开始之前就制定出测试计划。
- 把 Pareto原理应用到软件测试中。Pareto原理说明,测试发现的错误中的80% 很可能是由程序中20%的模块造成的。当然,问题是怎样找出这些可疑的模块并彻底地测试它们。
- 应该从“小规模”测试开始,并逐步进行“大规模”测试。
- 穷举测试是不可能的。
- 为了达到最佳的测试效果,应该由独立的第三方从事测试工作。所谓“最佳效 果”是指有最大可能性发现错误的测试。由于前面已经讲过的原因,开发软件的软件工程 师并不是完成全部测试工作的最佳人选(通常他们主要承担模块测试工作)。
测试方法:
黑盒测试法:如果已经知道了产品应该具有的功能,可以通过测试来检验是否每个功能都能正常使用。对于软件测试而言,黑盒测试法把程序看作一个黑盒子,完全不考虑程序的内部结构 和处理过程。也就是说,黑盒测试是在程序接口进行的测试,它只检查程序功能是否能按 照规格说明书的规定正常使用,程序是否能适当地接收输入数据并产生正确的输出信息, 程序运行过程中能否保持外部信息(例如数据库或文件)的完整性。黑盒测试又称为功能测试。
白盒测试法:如果知道产品的内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。白盒测试法与黑盒测试法相反,它的前提是可以把程序看成装在一个透明的白盒子 里,测试者完全知道程序的结构和处理算法。这种方法按照程序内部的逻辑测试程序,检 测程序中的主要执行通路是否都能按预定要求正确工作。白盒测试又称为结构测试。
测试步骤:
- 模块测试:目的是保证每个模块作为一个单元能正确运行,所以模块测试通常又称为单元测试。在这个测试 步骤中所发现的往往是编码和详细设计的错误。
- 子系统测试:目的是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间 的协调和通信是这个测试过程中的主要问题,因此,这个步骤着重测试模块的接口。
- 系统测试:目的是把经过测试的子系统装配成一个完整的系统来测试。在这个过程中不仅应该发现设计和编码的错误,还应该验证系统确实能提供需求说明书中指定的功能,而且系统的动态特性也符合预定要求。在这个测试步骤中发现的往往是软件设计中的错误,也可能发现需求说明中的错误。
不论是子系统测试还是系统测试,都兼有检测和组装两重含义,通常称为集成测试。
- 验收测试:目的是验证系统确实能够满足用户的需要,在这个测试步骤中发现 的往往是系统需求说明书中的错误。验收测试也称为确认测试。
- 平行运行:同时运行新开发出来的系统和将被它取代的旧 系统,以便比较新旧两个系统的处理结果。
3.1 单元测试
通常,单元测试主要使用白盒测试技术,而且对多个模块的测试可以并行地进行。
测试重点如下:
3.1.1 模块接口
首先应该对通过模块接口的数据流进行测试,如果数据不能正确地进出,所有其他测试都是不切实际的。
在对模块接口进行测试时主要检查下述几个方面:参数的数目、次序、属性或单位系 统与变元是否一致;是否修改了只作输入用的变元;全局变量的定义和用法在各个模块中 是否一致。
3.1.2 局部数据结构
对于模块来说,局部数据结构是常见的错误来源。应该仔细设计测试方案,以便发现局部数据说明、初始化、默认值等方面的错误。
3.1.3 重要的执行通路
由于通常不可能进行穷尽测试,因此,在单元测试期间选择最有代表性、最可能发现 错误的执行通路进行测试就是十分关键的。应该设计测试方案用来发现由于错误的计 算、不正确的比较或不适当的控制流而造成的错误。
3.1.4 出错处理通路
好的设计应该能预见出现错误的条件,并且设置适当的处理错误的通路,以便在真的 出现错误时执行相应的出错处理通路或干净地结束处理。不仅应该在程序中包含出错处 理通路,而且应该认真测试这种通路。当评价出错处理通路时,应该着重测试下述一些可 能发生的错误。
- 对错误的描述是难以理解的。
- 记下的错误与实际遇到的错误不同。
- 在对错误进行处理之前,错误条件已经引起系统干预。
- 对错误的处理不正确。
- 描述错误的信息不足以帮助确定造成错误的位置。
3.1.5 边界条件
边界测试是单元测试中最后的也可能是最重要的任务。软件常常在它的边界上失效,例如,处理\(n\)元数组的第\(n\)个元素时,或做到\(i\)次循环中的第\(i\)次重复时,往往会发生错误。使用刚好小于、刚好等于和刚好大于最大值或最小值的数据结构、控制量和数据值 的测试方案,非常可能发现软件中的错误。
3.2 集成测试
集成测试是测试和组装软件的系统化技术
自顶向下集成
自底向上集成
3.3 确认测试
确认测试也称为验收测试,它的目标是验证软件的有效性,通常使用黑盒测试法。
确认测试有下述两种可能的结果。
(1) 功能和性能与用户要求一致,软件是可以接受的。
(2) 功能和性能与用户要求有差距。
在这个阶段发现的问题往往和需求分析阶段的差错有关,涉及的面通常比较广,因此 解决起来也比较困难。为了制定解决确认测试过程中发现的软件缺陷或错误的策略,通 常需要和用户充分协商。
设计测试用例
基于GA的TSP问题
- 基本功能测试
- 输入:小规模距离矩阵,4个城市
- 预期输出:找到合理的最短路径
- 边界值测试
- 输入:最小距离矩阵,2个城市
- 预期输出:找到唯一的最短路径
- 随机输入测试
- 输入:随机生成的距离矩阵
- 预期输出:找到合理的最短路径
- 性能测试
- 输入:大规模距离矩阵
- 预期输出:在合理时间内找到较优解