第1章 软件开发概述
1.1 程序与软件
1.1.1 从程序到软件
1、软件
软件是有计算机程序和程序设计的概念发展演化而来,是程序和程序设计发展到一定规模后并且再逐步商品化的过程中形成的。
2、计算机程序的工程性和使用价值
- 计算机程序具有复制价值
- 计算机程序的生成是一种有多人合作、经历不同阶段的开发,且具有可复制和重复使用的器或件
3、计算机程序
(1)计算机程序简称程序,是为了解决某个特定问题而用程序设计语言描述的适合计算机处理的语句序列。
(2)软件是能够完成预定功能和性能的可执行的程序和使程序正常执行所需要的数据,加上描述软件开发过程及其管理、程序的操作和使用的有关文档,即“软件=程序+数据+文档”。
4、举例
教学管理系统。
1.1.2 软件类型
1、按功能划分
- 系统软件:如计算机操作系统、设备驱动程序、通信处理程序、网络管理程序。
- 支撑软件:如IDE、编译程序、文件格式化程序、DBMS、应用框架与程序库。
- 应用软件:包括商业数据处理软件、工程与科学计算机软件、管理信息系统、办公自动化软件、计算机辅助教学软件、游戏娱乐类软件、社交通信类软件等。
2、按各种方式划分
- 实时处理软件
- 分时软件
- 交互式软件
- 批处理软件
3、按服务对象范围划分
- 项目软件
- 产品软件
4、其他分类
- 商业软件
- 开源软件
- 共享软件
5、软件开发
随着软件变得越来越大、越来越复杂,软件开发的关注点也发生了变化,相对于小规模的程序设计,提出了大规模的程序设计,即软件开发。
1.1.3 程序设计与软件开发
1、计算机程序的两种形式
- 可执行程序
- 可读源代码
2、程序设计
以某种程序设计语言为工具,编写源程序,然后由编译系统完成可执行代码的转换。
3、程序设计活动
程序设计活动包括分析、设计、编码、测试、排错等。
4、程序=算法+数据结构
数据结构指程序处理或应用的数据之间的逻辑关系。算法是指解决特定问题的步骤和方法。程序设计的核心是选择和设计适合特定问题的数据结构和算法,用编程语言编制为程序。
5、软件工程
随着计算机技术的发展,软件规模变得越来越大,软件已经不可能仅仅依靠个人才能去编写与开发了,而是需要团队。程序设计活动走向软件工程,软件工程把经时间考验而证明正确的管理技术和当前能够得到的最好技术方法结合起来,以系统性的、规范化的、可定量的过程化方法去开发和维护。
1.2 软件生存周期
1.2.1 使用角度的软件生存周期
从用户角度可分为三个阶段:
1、提出需求
根据用户需求,提出要解决的问题和需要的软件。
2、获取软件
对获取软件的最佳途径做出决策并选择最佳的供应商。软件的获取有三种主要途径:
- 购买软件
- 定制或开发软件
- 租凭软件或租凭服务
3、使用软件
一旦获得软件之后,用户操作软件使之为其服务。
1.2.2 开发角度的软件生存周期
一般分为:定义软件、开发软件和维护软件。
1、需求定义
- 功能性需求:定义软件再抽象级别应该提供的基本功能。
- 非功能性需求(特性需求):软件应该具备的特性,如可用性、性能、安全性、可靠性等。
- 需求定义阶段一个重要部分是建立一组系统应该满足的总体目标。
2、软件设计
如何实现需求的决策和方案,是将系统功能分配到不同组成元素的过程,包括一组活动:
- 划分需求:对需求进行分析并合并成相关的组。
- 确定子系统:识别出独立或集体满足需求的子系统。
- 给子系统分配需求:原则上只要子系统的识别是需求划分驱动的,这个过程可省略。但在实践过程中,需求划分和子系统匹配从来都是不完全匹配的,使用外部系统或库函数可能会要求更改需求。
- 定义子系统:确定每个子系统或模块的特殊功能。
- 定义子系统的接口:定义每个子系统提供的或需要的接口。
经典的软件工程将软件设计分为:
- 概要设计
- 详细设计
3、软件实现
完成可运行程序及数据的软件开发过程。
4、软件维护
对已完成开发并发布、交付使用的软件产品进行完善、纠正错误、改进性能和其他属性,或使软件使用改变了的环境。软件维护分为四种类型:
- 改正性维护
- 适应性维护
- 完善性维护
- 预防性维护
1.3 软件开发过程
1.3.1 瀑布式开发过程
1、瀑布式开发过程
也叫软件生存期模型。它按照软件生命周期,把开发分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护这6个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。
2、核心思想
按工序将问题化简,将功能的实现与设计分开,便于分工协作,即采用结构化的分析与设计方法将逻辑实现与物理实现分开。
3、特性
强调文档的作用,并要求每个阶段都要仔细验证。
4、存在的问题
- 阶段划分僵硬,每个阶段不能缺省,而且产生了大量文档,增加了工作量。
- 开发是线性的,只有等到整个过程的末期才能见到开发成果——可运行软件,不利于快速响应变化的需求。
- 早期的错误要等到开发后期的测试阶段才能发现,可能带来严重的后果,增加了开发的风险。
1.3.2 增量开发模型
1、增量开发
增量开发特指待开发的软件不是一次就能完成,而是把软件分成一系列增量,完成一部分就交付一部分。对每个增量的使用和评估都作为下一个增量发布的新特性和功能。这个过程在每个增量发布后不断重复,直到产生了最终的完善产品。
2、基本思想
让开发者能够从早期的开发、系统的增量、交付的版本中学到经验。从系统的开发和使用中学习一切可能学到的东西。过程中的关键是从系统需求的简单子集实现开始,通过迭代增强和进化后续版本,直到系统被实现。每次迭代中,对设计进行修改,并增加新的功能要求。
3、特性
引进了包的概念,无需等到所有需求明确,只要某个需求明确了,就可以进行开发。
4、优点
- 短时间内交付一个可运行软件,解决一些急用功能。
- 每次只交付一部分,用户有较充分的时间学习和适应新的产品。
- 灵活使用需求的变化。
- 有利于系统维护。
5、存在的风险
- 由于各部件是逐步并入已有软件,必须确定每次增加的部件不破坏已构建好的系统,这需要软件具备开放式的系统结构,否则系统将失去稳定的结构。
- 逐步增加不见的方式,很容易退化成边做边改模型,从而使软件过程的控制失去整体性。
- 如何一致的定义“增量”?如何界定它的工作量、需求范围、功能或特性?
1.3.3 个体软件过程
1、PSP
- PSP是一种可用于控制、管理和改进个人工作方式的自我持续改进过程。
- 它是一个包括软件开发表格、指南和规程的结构化框架。
- PSP 与具体的技术(程序设计语言、工具或设计方法)相对独立,其原则能够应用到任何软件工程任务之中。
- PSP能够说明个体软件过程的原则。
- 帮助软件工程师做出准确的计划。
- 确定软件工程师为改善产品质量要采取的步骤。
- 建立度量个体软件过程改善的基准。
- 确定过程的改变对软件工程师能力的影响。
2、个体软件过程
- PSP0的目的是建立个体过程基线,学会使用PSP的各种表格采集过程的有关数据,执行的软件过程包括计划、设计、编码、编译和测试。按照选定的缺陷类型标准、度量引入的缺陷个数和排除的缺陷个数等,用在测量PSP过程的改进。PSP0.1增加了编码标准、程序规模度量和过程改善建议三个关键过程域。
- PSP1的重点是个体计划,用自己的历史数据来预测新程序的大小和需要的开发时间,并使用线性回归方法计算估计参数,确定置信区间以评价预测的可信程度。PSP1.1增加了对任务和进度的规划。在PSP1阶段应该学会编制项目开发计划,这不仅对承担大型软件的开发十分重要,即使是开发小型软件,也必不可少。
- PSP2的重点是个体质量管理,根据程序的缺陷建立检测表,按照检测表进行设计复查和代码复查(也称“代码走查”),以便及早发现缺陷,使修复缺陷的代价最小。PSP2.1则论述设计过程和设计模板,但并不强调选用什么设计方法,而强调设计完备性准则和设计验证技术。
- PSP3的目标是把个体开发小程序所能达到的生产效率和生产质量延伸到大型程序;其方法是采用迭代增量式开发方法,首先把大型程序分解成小的模块,然后对每个模块按照PSP2.1所描述的过程进行开发,最后把这些模块逐步集成为完整的软件产品。在新一轮开发循环中,可以采用回归测试。
1.4 敏捷开发
1.4.1 概述
1、价值观和基本原则
(1)4个核心价值观
- 个体和互动胜过流程和工具。
- 工作的软件胜过详尽的文档。
- 客户合作胜过合同谈判。
- 响应变化胜过遵循计划。
(2)12条原则
- 最优先要做的是通过尽早地、持续地交付有价值的软件满足客户需要。
- 即使在开发后期也欢迎需求的变化,敏捷过程利用变化为客户创造竞争优势。
- 经常交付可以工作的软件,从几星期到几个月,时间越短越好。
- 业务人员和开发人员应该在整个项目过程中始终朝夕在一起工作
- 要善于激励项目人员,给他们以所需要的环境和支持,并相信他们能够完成任务。
- 在开发小组中最有效率、也最有效果的信息传达方式是面对面的交谈。
- 工作的软件是进度的主要度量标准。
- 责任人、开发者和用户应该维持长期、恒等的开发节奏。
- 对卓越技术与良好设计的不断追求将有助于提高敏捷性。
- 简单——尽可能减少工作量的艺术——至关重要。
- 最好的架构、需求和设计都源于自组织的团队。
- 每隔一定时间,团队都要总结、反省工作效率,然后相应地调整自己的行为。
2、基本技术
- 敏捷方法可以视为一些最佳实践的集合,包括经典的软件开发技术和管理,也包括敏捷开发首创的技术和方法。
- 敏捷开发遵循软件开发的基本原则,同时也总结出了11条面向对象设计的原则,如单一职责原则(模块内聚的体现)、(采纳的)Liskov替换原则等。
- 敏捷开发主要采用了面向对象的开发技术,使用CRC卡( Class-Responsibility-Collaborator,类-责任-协作)、用户用例、设计模式及UML ( Unified ModellingLanguage,统一建模语言)。
- 使用UML 的符号主要是类图和时序图,这两种符号有助于直接编写出代码。
- 敏捷开发增强和推广了一些经典的实践,如意图导向编程,指的是先假设当前这个对象中已经有了一个理想方法,它可以准确无误地完成想做的事情,而不是直接盯着每一点要求来编写代码。
3、敏捷技术
- 结对编程:两个程序员在一个计算机上共同工作。一个人输入代码,另一个人审查他输入的每一行代码。两个程序员经常互换角色。
- 代码重构:指的是改变程序结构而不改变其行为,以便提高代码的可读性、易修改性等。例如,给变量重新命名,把一段代码提升为函数,把公共的属性和行为抽象成基类。
- 测试驱动开发:在一个微循环开发中,首先确认并自动化进行一个失败的测试,然后编写足够的代码通过测试,在下一轮前重构代码。
- 持续集成:微软等公司的软件开发方法包括每日构造产品,持续集成比它更进一步,只要可能,就把新代码或变更的代码合并到应用程序,然后测试,确保每一步的工作都正确。
1.4.2 Scrum方法
1、3个角色
- 产品负责人
- 产品经理
- 团队
2、3个工件
- 产品冲压工作
- 冲刺清单
- 燃尽图
3、5个活动
- 冲刺计划会议
- 每日站会
- 冲刺评审会议
- 冲刺回顾会议
- 产品积压工作梳理会议
4、5个价值
- 承诺
- 专注
- 开放
- 尊重
- 勇气
1.5 软件构造
1.5.1 有关概念
通过程序设计(Programming)、编码(Coding)得到程序、语句(段),书写(Write)文档或程序,设计(Design)包括软件及其构件、类、函数、算法、数据结构等的软件工件,也通过开发(develope)得到软件或程序。伴随着程序成为软件、作为产品或系统,程序员或软件开发者使用可复用技术、集成技术等把一个软件的不同组成部分按照一定的结构、通过一系列步骤组装(Assemble)成可运行的软件。建造(Build)与程序的编译有关,它可以把一个或一组源程序文件翻译成可执行的指令序列;也可以把构成一个软件的所有源程序文件、配置文件、数据文件及它们需要的库文件等,按照一定的顺序编译并连接成一个可运行文件。Meyer:面向对象软件构造是一种软件开发方法,是运用面向对象技术开发具有结构的软件系统,其结构组成是类;类可以立即实现,也可以延迟实现(从而具有动态性)。因而,软件具有房屋建造的特点,是使用了预制的、可复用的建造部件,按照(设计的)结构和流程而完成的产品。
1.5.2 构造与开发过程
- 构造在不同软件开发流程或模型中的地位也不一样。有些流程更加重视构造。
- 从构造角度看,有些模型侧重于线性化过程——比如瀑布模型、阶段交付的生命周期模型。线性化开发方式更加重视构造之前的活动(需求和设计),并且在这些活动之间建立明确的任务划分。在这些模型中,构造工作主要就是编码。
- 有些模型是迭代的——如Scrum、极限编程、进化式原型法。这些方式倾向于把构造视为与其他软件开发(包括需求、设计和计划)同时发生或重叠的活动。这些方式混合设计、编码和测试活动,把构造当成这些活动的集合体。
- 如何考虑构造,在某种程度上依赖于采用的生存周期模型。一般地说,软件构造最主要是编码和调试,但也可以包含工作计划、详细设计、单元测试、集成测试,以及其他活动。
1.5.3 主要内容
- 软件构造基础
- 管理构造
- 实际考虑
- 构造技术
- 软件构造工具
1.5.4 软件构造的重要性
- 占据了软件开发的大部分工作(30%~80%的工作时间)
- 是软件开发的中心活动
- 重心放在构造上,能显著提升个体程序员的生产率
- 构造的产品——程序源代码,常常是唯一标准的软件描述
- 构造是确保唯一要完成的活动
1.6 为什么不直接编写软件
1.6.1 软件开发语言
1、按计算模型划分
- 命令式语言
- 冯·诺依曼式语言
- 脚本语言
- 面向对象语言
- 声明式语言
- 函数式语言
- 逻辑式语言
- 高级程序语言
2、按执行模式划分
高级语言的程序不能直接上计算机运行,需要转换成低级语言的指令后才能运行。
- 编译型语言:C、C++、Ada
- 解释型语言:Python、Basic及脚本语言等
1.6.2 编程工具与集成化开发环境
- 编程的编程工具——软件开发工具包(Software DevelopmentKit,SDK),它通常包括编译程序或解释程序、调试程序、连接程序等,如Java的JDK、Android 的ADK。编写程序的工具是普通的文本编辑器,它可以是传统的正文行编辑器,也可以是面向全屏的图形编辑器。编辑器可以是通用的、与程序语言无关,也可以是具备源程序语言知识的语法制导编辑器或结构化编辑器(如emacs、notepad++)。
- 软件开发还需要管理各种代码文件、检查程序质量、测试工具、管理bugs、软件打包工具等。这些基础开发工具通常是行式命令,直接在操作系统中输入相应的命令,如编译Java程序的编译命令javac,解释执行Java程序的命令java。也有一些语言直接提供可视化开发工具。
- 可视化集成开发环境IDE,用图形用户界面(Graphical UserInterface , GUI)集成了代码编写、静态分析、编译、调试、连接、打包等功能的一体化软件开发套件。支持多种语言进行编程,还提供代码管理、代码分析、软件维护、软件测试及软件部署和交付等工具,同时支持多种形态应用软件(通用程序、Web应用、数据库应用、移动应用)的开发。如Delphi、Visual Studio、Eclipse和Netbeans。
1.6.3 软件运行环境
1、软件运行环境
软件运行环境,广义上说,是一个软件运行所要求的各种条件,包括软件环境和硬件环境。许多应用软件不仅仅要求特定的硬件条件,还对软件提出明确的支撑条件。操作系统将计算机的硬件细节屏蔽,将计算机抽象成虚拟资源。通常把计算机硬件和操作系统称为平台。
2、虚拟机
- 为了能够使同一种编程语言的程序独立于操作系统,实现程序运行的独立性,即“一次编写程序、到处运行”,在操作系统层面提出并出现了语言虚拟机或运行容器。它为程序的运行提供所需的运行时资源,包括把程序翻译成计算机指令、分配内存、通过操作系统调用计算资源等。
- 例如,Java 虚拟机 (Java Virtual Machine ,JVM)可以理解成一台运行Java程序的抽象的计算机。
3、支撑环境
- 使用的数据库管理系统,如Oracle、MySQL、SQL Server。
- Web 服务器,如Apache服务器、Tomcat服务器
- 应用框架,如.NET Framework、Java程序的SSH 框架、Web 应用框架Ruby on Rails。
- 第三方程序库、APIs,如大数据分析与处理的Panda,人工智能的TensorFlow, Caffe、Torch,等。
1.6.4 软件开发的最佳实践
1、最佳实践
- 用户满意的、可以反复使用的软件开发的一切手段
- 最佳实践认为存在某种技术、方法、过程、活动或机制可以使生产或管理实践的结果达到最优,并减少出错的可能性。
2、原则
一个已经接受或专业化的指导行动的最高准则或标准。人们总结、使用了软件开发的基本原则、面向对象原则等。原则必须通过某种途径体现出来,才具有指导作用。
3、机制
指的是有机体的构造、功能及其相互关系、工作原理,如可视化编程的事件响应机制、类型的多态机制。
4、技术
是科学原理的应用,是具有技能特点的特殊的步骤或途径。软件开发技术是运用了计算机科学、数学、系统科学、管理科学的基本原理,进行软件开发的方式方法。
5、方法
是获得一个客体(对象)的步骤或过程。作为一个系统的步骤、技术活动被特定的专业或艺术采纳,是技能或技术的全部。研究方法及其知识的活动称为方法学,如面向对象方法学
6、工具
工具指的是执行操作的器具,引申为为达到、完成或促进某一事物的手段。我们使用更加广泛的含义,软件工具指的是从编辑器、编译器、自动化测试框架到IDE的实用程序。
1.6.5 开发过程与管理
软件开发不像计算机、手机的制造等可以使用机器设备进行大规模的自动化生产。软件开发主要是人的智力活动,而且很多时候是一群人的开发活动。
- 首先,软件开发是做出决策、权衡和选择的过程。
- 对于人员管理,首先要识别出参与软件开发、与软件开发相关、受软件影响的人员,并分析每个相关人员对软件的诉求、期望、影响和作用。
- 软件开发作为项目要评估成本、质量、人员等因素,预先做出项目计划。
第2章 模块化软件构造
2.1 分解与模块化
2.1.1 分解的含义
- 把问题分解成两个或多个更小的问题
- 分别解决每个小问题
- 然后把各个小问题的解答结合起来,即可得到原问题的解答。
2.1.2 模块化与结构化
1、模块化
(1)模块化
- 模块化是把问题分解成容易理解、便于控制、便于实现的子问题的一个重要手段,是实现控制复杂性的方式。
- 模块化把一个程序分解成简单独立、互相作用的模块,对不同的模块设定不同的功能,来实现大型、复杂的程序。
- 在程序系统的结构中,模块是可组合、可更换的程序单元。
- 良好的模块设计只完成一个特定的或一组相关的子功能。
- 所有模块按某种方式组装起来,成为一个整体,完成整个系统所要求的功能。
(2)软件模块
- 具有相对独立性、由数据说明、执行语句等程序对象构成的代码集合。
- 程序中的每个模块都需要单独命名,通过名字可实现对指定模块的访问。
- 一个模块具有输入/输出(接口)、功能、内部数据、程序代码4个特征。
(3)模块的三大特征
- 独立性:可以对模块单独进行设计、编码、调式、修改和存储。
- 互换性:模块具有标准化的接口,容易实现模块间的互换。
- 通用性:有利于实现系列产品间的模块的通用,实现跨系列产品间的模块的通用。
(4)模块化的好处
- 有助于了解软件设计,使结构清晰,容易阅读和理解。
- 使软件容易测试和调试。
- 提高软件的可修改性。
- 有助于软件开发工程的组织管理,一个复杂的大型程序可以有许多程序员分工编写不同的模块,并且可以进一步分配技术熟练的程序员编写困难的模块。
2、结构化
- 图灵奖获得者Wirth提出的“结构化程序设计”(Structured Programming)的方法,可以简化为“算法+数据结构=程序”。
- 该方法的重点是:不要求一步就编写成可执行的程序,而是分若干步进行,逐步求精。
- 第一步编写出的程序抽象程度最高,第二步编出的程序抽象程度有所降低……最后编出的程序即为可执行的程序。
- 优点:使程序易读、易写、易调试、易维护,也易于保证程序的正确性及验证其正确性。
- 这种结构化设计方法又称“自顶向下”或“逐步求精”法,在程序设计领域引发了一场革命,成为程序开发的一个标准方法。
2.2 数据结构与算法
2.2.1 数据结构与算法的关系
1、数据结构
- 数据结构是计算机存储、组织数据的方式,是指相互之间存在的一种或多种特定关系的数据元素的集合。
- 数据结构为数据集提供独立于计算机内存的数据组织,并提供被视为一种抽象工具来访问。
- 常见的数据结构有数组、集合、栈、队列、堆、树、图、散列表等。
2、计算机算法
- 计算机算法以一步一步的方式来详细描述计算机如何将输入转化为所要求的输出的过程。
- 描述算法的方式可以采用自然语言、程序设计语言,也可以两种语言混合使用。
- 用计算机程序语言实现并在计算机上运行的算法就是程序,它是一个解决实际问题方法的程序语言的指令序列。
- 基本的算法类型包括查找(顺序查找、二分查找)、排序(冒泡排序、快速排序、插入排序、归并排序等)、二叉树的遍历(前序遍历、中序遍历、后序遍历)、图的遍历(广度优先遍历、深度优先遍历)、最短路径算法。
3、两者关系
- 一种数据结构、一种算法:如计算树的高度、树节点的层级。
- 一种数据结构、多种算法:数组支持的算法有排序算法、查找算法、图类算法、矩阵类算法等。
- 多种数据结构、一种算法:折半查找,使用的基本数据结构有数组、二叉树,也可以使用链表。
- 多种数据结构、多种算法:针对数据结构数组和二叉树,基本的算法有遍历类、查找类、求最大值。
2.2.2 选择与设计数据结构
1、算式与习题的基本数据结构
(1)设计1:
包含两个运算数,一个运算符及结果的数据结构
typdef struct equation{
unsigned short int left_operand, right_operand;
char operator;
unsigned short int value;
}
需要注意:
1)命名:见名知意
2)一个结构类型是否包含非独立变量,应该考虑下列因素:
- 获取非独立变量值的难易程度:比较简单的话不需要在结构体中定义,比较复杂,消耗资源则可用一个变量记录该值。
- 使用非独立变量的频繁程度:使用频繁且值比较稳定,考虑包含非独立变量;否则不包含。
(2)设计2
用一个数组[operand,operand2,operator]表示算式Equation。
2、比较
3、算法分析与其它数据结构
- 算法分析:产生有正整数n个不同算式的习题,算法的复杂度是O(n^2)。
- 其它数据结构:集合
2.2.3 选择与设计算法
1、习题与算式的分离
把习题和算式明确地从代码中抽出,并分别用合适的数据结构表示,有助于各自的设计与实现,也能实现不同的算式和习题的任意组合。
2、算式产生与其约束条件的分离
分别定义运算数生成函数与约束条件检测函数,对满足一定条件的运算数才生成算式。这样,约束条件的任意变换都不影响算式生产函数,也支持用户灵活设置约束条件。
3、加减法算式的分离
便于生产混合运算。
2.3 模块化设计理论初步
2.3.1 模块化原则
1、Meyer提出了5条标准来评价一种设计方法是否定义了有效的模块系统能力:
- 可分解性
- 可组装性
- 可理解性
- 连续性
- 保护性
2、模块的独立程度可以由两个定性标准来度量:
- 内聚:衡量一个模块内部各个元素之间相互结合的紧密程度
- 耦合:衡量不同模块彼此之间相互依赖(连接)的紧密程度
2.3.2 模块的内聚性
内聚性越高,相对地,它与其它模块之间的耦合度就会降低,模块越独立。内具有7种,由弱到强排列如下:
- 偶然内聚
- 逻辑内聚
- 时间内聚
- 过程内聚
- 通信内聚
- 顺序内聚
- 功能内聚
2.3.3 模块间的耦合性
开发中尽量追求松耦合,耦合度从低到高可分为7级:
- 非直接耦合
- 数据耦合
- 标记耦合
- 控制耦合
- 外部耦合
- 公共耦合
- 内容耦合
2.4 测试程序
2.4.1 测试需求
- 首要任务就是分析用户需求与设计,梳理含糊不清、模棱两可、互相矛盾的需求,明确、细化和罗列出需求,并且将每个需求表示成可以检测的测试需求。
- 其次,测试需求要求程序的预期结果和实际运行结果都要明确、合理、可观察并可比较。
- 找到隐含需求或隐含的不确定因素也需要进行测试。
2.4.2 测试设计与测试用例
测试设计包括测试用例的设计,此外还包括是否实施所有层次的测试,是否采用测试工具或自动化测试框架、哪些测试采用哪些工具,如何组织人员等等。
程序的运行结果可以分成以下三类:
- 产生的值
- 状态变化
- 必须一起解释为输出才有效的一个序列或一组值
测试数据全部通过,说明待测试程序在一定程度上满足需求或功能要求。测试结果的判定可能会存在误判和漏判。
待测程序使用测试用例的3种方式:
- 程序员每次从键盘输入一个测试数据,观察测试结果并和预期值比较,记录测试通过与否。
- 程序员通过编写测试程序,先存储测试用例,然后让待测程序逐个读取测试数据、运行、比较预期结果,同时记录测试结果。
- 使用测试工具完成测试程序的操作及其他更多操作。
2.5 调式测试
2.5.1 缺陷的相关术语
软件Bug的准确术语是缺陷(Defect),就是软件产品中所存在的问题,最终表现为用户所需要的功能没用完全实现,不能满足或不能全部满足用户的需求。从产品内部看,软件缺陷是软件产品开发或维护过程中所存在的错误、毛病等各种问题;从产品外部看,软件缺陷是系统所需要实现的某种功能的失效或违背。
软件缺陷源自人的过失活动产生的不正确结果,导致在软件产品、模块中出现了缺陷或故障。
所谓错误就是导致不正确结果的全部。它展示了某个故障的不正确的内部状态。可以理解Bug是程序中引起错误的具体位置,因此,debug就是找出并更改程序中的错误。
2.5.2 调式基础
- 科学的调式过程
- 定位程序缺陷
- 更正缺陷
2.6 讨论与提高
2.6.1 软件质量
ISO定义的6个独立的质量特性:
- 功能性:程序是否满足了用户需求
- 可靠性:程序保持规定的性能水平的能力
- 可用性:程序有多容易使用
- 效率:与程序运行时消耗的物理资源有关
- 可维护性:是否容易修改程序
- 可移植性:是否容易把程序移植到一个新的环境
2.6.2 软件测试的其它观点
- 正面观:证明软件是正确的。
- 负面观:证明程序有错误。
- 风险角度:对软件系统中潜在的各种风险进行评估的各种活动。
- 经济角度:以最小的代价获得高质量的软件。
2.6.3 测试设计
1、覆盖测试
(1)覆盖测试
测试所包含的软件的特征、元素、成分等方面的程度或范围。
(2)原则
- 多覆盖域原则:满足一个测试覆盖不能为软件的正确程度提供充足的保证。
- 测试覆盖原则:度量测试覆盖率并针对不断增强的覆盖率来改进测试数据,就能改进待测软件。
2、基于等价类划分的测试
等价类划分的两种不同情况:
- 有效等价类
- 无效等价类
划分原则:
- 按区间划分
- 按数据集合划分
- 按限制条件划分
- 按限制规则划分
- 按输入方式划分
- 细分等价类
3、基于边界值分析的测试
基本策略
- 若输入条件指定了以a和b为边界的范围,则测试数据应该包括a,b,略大于a,略小于b,刚刚小于a,刚刚大于b的值作为非法的测试数据。
- 若输入条件规定了输入值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多个的数作为测试数据。
- 如果程序的规格中说明给出的输入域或输出域是有序集合,则应该选取集合的第一个元素和最后一个元素作为测试用例。
- 如果程序中使用了一个内部数据结构,则应该选择这个内部数据结构的边界上的值作为测试用例。
- 分析用户需求和软件设计,找出其它可能的边界条件。
2.6.4 编程风格
- 标识符的命名域使用
- 注释
- 排版与布局:一致、符合常规、简明