软件工程-第4章 结构化系统的实现

软件工程

第4章 结构化系统的实现

4.1 编码

编码目的

把模块的过程性描述翻译为用选定的程序设计语言书写的源程序(源代码)。

依据

编码的主要依据是概要设计和详细设计说明文档**。**

任务
  • 理解概要设计和详细设计说明书;
  • 遵循编码原则和风格进行翻译,形成源代码。
程序设计语言的分类
  • 机器语言
    • 优点:计算机直接识别
    • 缺点:效率低,重用性差
  • 汇编语言(机器指令助记符)
    • 优点:
      • 比机器语言易读写、易调试和修改
      • 执行速度快、占内存少
      • 针对硬件编制
    • 缺点:
      • 不能编写复杂程序
      • 依赖于机型、不通用、不可移植
  • 高级语言(与自然语言相近,面向用户的语言)
    • 优点:
      • 编码效率高
      • 通用性强,兼容性好,便于移植
    • 缺点:
      • 运行效率低
      • 对硬件操作不如汇编
语言选择标准
  • 系统用户要求
    • 如果开发系统由用户维护,通常要求用熟悉的语言书写
  • 可以使用的编译程序
    • 运行目标系统环境可提供编译程序限制可选用语言的范围
  • 可以得到的软件工具
    • 有支持程序开发的软件工具可以利用。
  • 工程规模
    • 规模庞大,现有语言不适用,设计实现供该工程项目使用程序设计语言。
  • 程序员知识
    • 如果和其他标准不矛盾,应选择程序员熟悉的语言
  • 软件可移植性要求
    • 若目标系统在不同计算机上运行,选择可移植性好的语言
  • 软件的应用领域
    • 选择语言时应充分考虑目标系统的应用范围。
编码风格

逻辑简明清晰、易读易懂是重要标准

编码遵循的规则
  • 程序内部的文档
    • 恰当的描述符
      • 含义鲜明
      • 命名规则一致
      • 避免过长或过短(建议英文)
      • 缩写规则一致
      • 函数用大写字母开头单词
    • 适当的注释:源程序中有效注解量在20%以上
      • 序言性注解(模块开始,描述模块功能、主要算法、接口特点、重要数据及开发简史(设计者、复审者及时间、修改日期))
      • 中间注解(插在程序中间,解释这段代码的必要性及功能)
    • 良好的视觉组织:空格、空行、缩进
  • 数据说明
    • 数据说明次序应标准化(按数据结构或数据类型说明)
      • 常量->简单变量->数组->公用数据块->文件
      • 整形->实型->字符->逻辑
    • 多个变量名在一个语句说明,按字母顺序排列。
    • 复杂数据结构用注解说明实现方法和特点。
  • 语句构造(简单)
    • 避免把多个语句写在同一行
    • 尽量避免复杂条件测试
    • 尽量减少“非”条件测试
    • 避免大量使用循环嵌套和条件嵌套
    • 利用括号使表达式运算次序清晰直观
    • 尽量少用goto语句
  • 输入输出
    • 对所有输入数据都进行检验,保证输入有效;
    • 检查输入项重要组合合法性;
    • 保持输入格式简单;
    • 使用数据结束标记,不要求用户指定数据数目;
    • 提示交互式输入请求,如可用选择或边界数值
    • 程序设计语言对格式有严格要求时,应保持输入格式一致;
    • 设计良好输出报表;
    • 给所有输出数据加标志
  • 效率(和存储容量)
    • 程序运行时间
      • 简化算术和逻辑表达式;
      • 嵌套循环,确定是否有语句可从内层往外移;例
      • 尽量避免使用多维数组;
      • 尽量避免使用指针和复杂的表;
      • 使用执行时间短的算术运算;
      • 不要混合使用不同的数据类型;
      • 尽量使用整数运算和布尔表达式。
    • 存储器效率
      • 大中型计算机考虑操作系统页式调度特点,将程序功能合理分块,每个模块或一组密切相关程序体积与每页容量相匹配,减少页面调度。
      • 微型计算机关键是程序简单性,选择生成较短目标代码且存储压缩性能优良的编译程序。
    • 输入输出效率
      • 所有输入/输出都应有缓冲,减少通信的额外开销;
      • 对二级存储器(如磁盘)选用最简单访问方法;
      • 辅助存储器的输入/输出以信息组为单位进行;
      • 如“超高效”输入/输出很难被理解不采用。

4.2 软件测试基础

软件测试的目标

(1)测试是为了发现程序中的错误而执行程序的过程;
(2) 好的测试方案是极有可能发现迄今尚未发现的尽可能多的错误的测试;
(3) 成功的测试是发现了迄今尚未发现的错误的测试。

黑盒测试和白盒测试
  1. 黑盒测试:如果知道产品应具有功能,可通过测试来检验是否每个功能都能正常使用。
  2. 白盒测试:如果知道产品内部工作过程可通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。
测试准则
  1. 所有测试应能追溯到用户需求,测试的目的是发现错误,其中最严重的是不能满足用户需求的错误。
  2. 应尽早地和不断地进行软件测试。不应把软件测试仅看作是软件开发一独立阶段,应把它贯穿到软件开发各阶段中。
  3. 充分注意测试中群集现象。测试后程序中残存错误数与程序中已发现错误数目成正比,80%错误与20%模块有关。
  4. 测试应从小规模开始,逐步进行大规模测试。单个模块,逐步集成。
  5. 不能做到穷举测试。
  6. 第三方测试原则:从心理学角度考虑。

4.3 逻辑覆盖

语句覆盖

选择测试数据,使被测程序中每个语句至少执行一次。

判定覆盖

每个语句至少执行一次,每个判定的真假分支至少执行一次。

条件覆盖

每个语句至少执行一次,判定表达式每个条件取各种可能结果。

判定/条件覆盖

取足够多测试数据,使判定表达式每个条件都取各种可能值,且每个判定表达式也都取到各种可能结果。

条件组合覆盖

选足够多的数据,使每个判定表达式中条件的各种组合都至少执行一次

4.4 控制结构测试

基本路径测试

一种白盒测试技术。

  1. 根据过程设计结果画出相应流图
  2. 计算流图的环形复杂度
  3. 确定线性独立路径的基本集合
    • 独立路径:至少包含一条在定义该路径之前不曾用过的边。
    • 环形复杂度为独立路径基本集的上界。
  4. 设计测试用例覆盖基本集合的路径

注意:
一些独立路径无法独立测试,程序的正常流程不能形成独立执行该路径所需的数据组合(需要满足total.valid>0),这种情况下这些路径必须作为其他路径的一部分来测试。

循环测试
  1. 简单循环
    • 零次循环:从循环入口直接跳到循环出口。
    • 一次循环:查找循环初始值方面的错误。
    • 二次循环:检查在多次循环时才能暴露的错误。
    • m次循环:此时的m<n。
    • 最大次数循环、比最大次数多一次循环、比最大次数少一次的循环。
  2. 嵌套循环
    • 从最内层循环开始,置所有其它层循环为最小值
    • 对最内层循环做简单循环的全部测试。
    • 逐步外推,测试时保持所有外层循环变量取最小值,其它嵌套内层循环变量取“典型”值。
    • 反复进行,直到所有各层循环测试完毕。
  3. 连锁循环
    • 各个循环互相独立,可用与简单循环相同方法进行测试。
    • 几个循环不是互相独立,需要使用测试嵌套循环。
  4. 非结构化循环
    • 使用结构化程序设计方法重新设计。

4.5 黑盒测试技术

黑盒着重测试:软件功能。

黑盒发现错误类型
  1. 功能不正确或遗漏
  2. 界面错误
  3. 数据结构或外部数据库访问错误
  4. 性能错误
  5. 初始化或终止错误
常见黑盒测试技术
  1. 等价类划分;
  2. 边界值分析;
  3. 错误推测等
等价类划分

把程序的输入域划分成若干数据类,从每一数据类选取少数有代表性数据做为测试用例。
在各数据类中,各输入数据对揭露程序中的错误等效。

1.划分等价类
  • 有效等价类:合理,有意义输入数据构成集合。
  • 无效等价类:不合理,无意义输入数据构成的集合。

等价类划分原则

  1. 输入条件规定范围,定义一有效等价类和两无效等价类。
  2. 输入条件是布尔量,一个有效等价类和一个无效等价类。
  3. 规定输入数据一组值,程序对每个输入值分别进行处理。每个输入值确立一有效等价类,针对这组值确立一个无效等价类。
  4. 规定输入数据必须遵守规则,定义一有效等价类(符合规则)和若干无效等价类(从不同角度违反规则)。
  5. 已划分等价类中各元素在程序中处理方式不同,将等价类进一步划分更小等价类。
2.确立测试用例

建立等价类表,列出所有划分出等价类:

  1. 为每一等价类规定一唯一编号;
  2. 设计一新测试用例,尽可能多覆盖尚未被覆盖有效等价类,重复,直到所有有效等价类被覆盖;
  3. 设计一新测试用例,仅覆盖一尚未被覆盖无效等价类,重复,直到所有无效等价类被覆盖。
边界值分析
  • 等价类划分补充;
  • 确定边界情况;
  • 选正好等于边界值做测试数据;
  • 选临近边界合法数据,刚超过边界非法数据。
边界选择原则
  1. 输入条件规定了取值范围,则以该范围作为边界;
  2. 输入条件规定值的个数,则以个数为边界;
  3. 针对规格说明的每个输出条件,使用原则(1)和(2);
  4. 如果规格说明给出的输入或输出域是有序集合(如有序表、顺序文件等),则选取集合中特定次序的元素作为边界,如第一个、最后一个元素等;
  5. 如果程序中使用了一个内部数据结构,则应选择该结构的边界上的值,如数组、链表等;
  6. 分析规格说明,找出其它可能边界条件。
错误推测法

靠经验和直觉推测程序可能存在错误,有针对性编写检查这些错误的测试用例。

注意:

  • 输入数据或输出数据为零
  • 输入或输出数目为零(如表空或只1项)
  • 缺省值
  • 空白空值
  • 多个数据的组合效应
  • 错误的群集现象

4.6 测试步骤

  • 单元测试
  • 集成测试
  • 系统测试
  • 验收测试
单元测试

模块通过编译的语法检查后进入单元测试。

  1. 模块接口
    数据是否正确进出模块。
  2. 局部数据结构
    局部数据的说明、初始化、默认值是否有问题。
  3. 重要执行路径
    重要执行路径是否有错误计算、不正确比较或不适当控制流。
  4. 出错处理通路
    (1)错误描述是否难于理解;
    (2)记下错误是否与实际遇到错误不同;
    (3)错误处理之前,错误条件已引起系统干预;
    (4)错误处理不正确;
    (5)描述错误信息不足以帮助确定错误位置;
  5. 边界条件
    最重要,软件容易在边界上失效。

测试方法

  1. 代码审查(人工)
    先由编写人非正式进行,再由审查小组正式进行,可查30%到70%设计错误和编码错误。
  • 程序编写者讲解,审查小组审查;
  • 预排演。
  1. 计算机测试
    需要辅助模块模拟与被测模块相联模块,两种:
  • 驱动模块──相当被测模块主程序。接收测试数据,传送 给被测模块,再输出测试结果。
  • 桩模块 ──存根模块。代替被测模块调用的子模块。
集成测试

测试与接口有关问题

  • 穿越接口数据是否丢失;
  • 一模块功能是否对另一模块功能产生不利影响;
  • 各子功能组合起来,能否达到预期的父功能;
  • 全局数据结构是否有问题;
  • 单个模块误差累积起来,是否会放大等。

  1. 非渐增式集成:把所有模块一次组装进行测试。
  2. 渐增集成:将模块逐步组装成较大系统。
    • 自顶向下集成;
    • 自底向上集成。
    • 混合策略
      • 改进的自顶向下测试方法:基本用自顶向下方法,早期用自底向上测试关键模块。
      • 混合法:软件结构上层模块用自顶向下,下层用自底向上
  3. 回归测试:重新执行已作过测试的某子集,保证变化没带来非预期副作用。
    • 回归测试集:
      • 检测软件全部功能的代表性测试用例;
      • 专门针对可能受修改影响的软件功能附加测试;
      • 针对被修改过软件功能测试
系统测试

使软件和其它系统元素(硬件、数据库等)结合测试。用于系统测试的测试类型:

  • 恢复测试:以不同方式强制软件出现故障,检测软件能否恰当完成恢复
    • 自动恢复:检测重新初始化、数据恢复、重新启动等是否正确。
    • 人工干预恢复:检测平均恢复时间是否在允许范围内。
  • 安全性测试:突破软件安全保护机构的安全保密措施,检验系统预防机制的漏洞。
    • 测试者扮演试图攻击系统角色:
    • 通过外部手段获取密码;
    • 通过客户软件攻击系统;
    • 控制系统使其他人无法访问;
    • 引发系统错误,期望在系统恢复中侵入系统等。
  • 强度测试:检验系统能力最高达到实际限度, 让系统处于资源异常数量、异常频率、异常批量条件下测试系统承受能力。一般比平常限度高5-10倍的限度做测试用例。
  • 性能测试:软件运行性能与性能要求比较,检验是否达到性能要求规格(例如时间需求)。
验收测试

系统测试后,客户再验收测试。确认测试以需求规格说明书为测试基础;采用黑盒法。

α测试

用户对即将面市软件产品(称α版本)进行测试,开发者坐在用户旁边,随时记下错误情况和使用中问题,是受控环境下测试。

目的: 评价软件功能、可使用性、可靠性、性能、界面。

β测试

多个用户在实际使用环境下进行的测试。用户与公司签定支持产品预发行合同,使用产品,并返回错误信息。是在开发者无法控制的环境下进行的软件现场应用。

目的: 产品的支持性。

4.7 调试

软件调试是在进行了成功的测试之后才开始的工作。它与软件测试不同,调试的任务是进一步诊断和改正程序中潜在的错误。

调试活动

  • 确定程序错误的性质和位置。
  • 修改程序,排除错误。
调试步骤
  1. 从错误现场入手,确定程序出错位置;
  2. 找错误的内在原因;
  3. 找到则排除错误,回归测试。
  4. 否则,加测试用例证明猜测原因。
调试方法
  1. 强行排错
    • 将内存内容打印出来分析;
    • 程序特定部位设置打印语句。
      • 各关键变量改变部位、重要分支部位等,监视重要变量变化。
    • 自动调试工具。
      • 程序语言调试功能或专门交互式调试工具,不必修改程序。如设置断点,观察程序断点处状态,包括变量、表达式值等。
  2. 回溯法排错(小程序常用)
    确定最先发现“症状”位置。人工沿程序控制流程向回追踪源代码,直到找到错误根源或确定错误产生范围。
  3. 原因排除法
    • 对分查找法
      • 如已知每个变量在程序内若干关键点正确值,用赋值或输入语句在程序中点附近“注入”正确值,运行程序检查输出。
      • 正确,错误原因在程序上半部分;反之,在程序后半部分。
      • 反复使用,将程序出错范围缩小到容易诊断的程度。
    • 归纳法
      • 归纳法是一种从特殊推断一般的逻辑方法。
      • 归纳法调试的想法是:从一些线索(错误征兆)着手,通过分析它们之间的关系来找出错误。
    • 演绎法:演绎法是从一般原理或前提出发,经过排除和精化的过程来推导出结论的逻辑方法。
      • 根据已有测试用例,设想所有可能出错原因;
      • 逐个排除不正确的;
      • 验证余下假设确是出错原因。

4.8 软件可靠性

可靠性:程序在给定时间间隔及环境条件下,按规格说明书的规定,成功运行的概率。
可用性:给定的时间点,按规格说明书规定,成功运行概率。

估算平均无故障时间
估算错误总数方法
  1. 植入错误法
    测试之前由专人在程序中随机植入错误,测试后,根据发现错误中原有的和植入的两种错误的比例,估计程序中错误总数。
  2. 分别测试法
    如果能对程序中原有的错误加上标记,然后再通过进一步的测试,就可以对潜在故障进行估计。
    由甲乙两测试员分别测试,一测试员测出错误作为有标记错误。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值