软件工程【四】

二、结构化设计(续)


6、过程设计(详细设计)

(1)过程设计任务

确定模块算法、确定模块使用数据结构、确定模块接口(系统外部接口、用户界面、内部模块间接口细节、输入数据和输出数据)

实际上就是具体如何实现模块功能,对此进行详细设计

(2)结构化程序设计

结构化程序设计定义:

  • 经典定义:程序代码通过顺序、选择、循环三种控制结构连接,单入口单出口。
  • 扩展定义:可限制使用GOTO语句、DO_UNTIL和DO_CASE
  • 修正定义:LEAVE和BREAK,可从循环中转移出来。

实际上就是合理使用顺序、选择、循环、和一些控制语句进行程序设计。

(3)结构化程序设计工具

①程序流程图

程序流程图是历史最悠久、使用最广泛的过程设计工具。

  • 国内常用的表示符号:

  • 标准的表示符号

  • 求n的阶乘算法表示实例

优点:对控制流程描绘直观,便于初学者掌握。

缺点: (1)不是逐步求精好工具,过早考虑控制流程,非整体结构;
(2)用箭头代表控制流,程序员随意转移控制;
(3)不易表示数据结构和调用关系。

②N-S图

  • 计算n阶乘的N-S图:

特点:

(1)功能域(一特定控制结构的作用域)明确;

(2)不可能任意转移控制;

(3)容易确定局部和全程数据的作用域;

(4)容易表现嵌套关系,也可表示模块的层次结构。

③PAD图

  • 可逐步求精:

  • 计算n阶乘的PAD图

优点:

(1)使用PAD图设计的程序必然是结构化程序;

(2)PAD图描绘的程序结构十分清晰;

(3)用PAD图表现程序逻辑,易读、易懂、易记;

(4)容易将PAD图转换成高级语言源程序;

(5)支持自顶向下逐步求精。

④判定表

能清晰表示复杂的条件组合与应做动作间对应关系。

左上部列出所有条件;左下部所有可能做的动作;右上部表示各种条件组合的一矩阵;右下部是和每种条件组合相对应的动作。

  • 例:行李托运算法的判定表

行李种类<=30都免费,所以只设为一个组合,其他三个自由组合2^3+1=9种。每种对应的方案用‘X’表示

⑤判定树

判定表变种,表示复杂条件组合与应做动作间对应关系。更加直观。

优点:形式简单,易看出含义,易于掌握和使用。

缺点:简洁性不如判定表,相同数据元素重复写多遍,越接近叶端重复次数越多。

(4)程序复杂度

介绍使用比较广泛的McCabe方法

1.根据过程设计结果画出相应流图

流图描述程序控制流,基本图形符号如下图所示。

2.计算流图的环形复杂度

三种方法:

  • V(G)=区域数
  • V(G)=E-N+2 E为流图中边数,N为流图中节点数
  • V(G)=P+1 P为判定点数

例子:

  • *V(G)=4 (区域数) *
  • *V(G)=11(边数)-9(结点数)+2=4 *
  • V(G)=3(判定结点数)+1=4

取任意一种方法即可,区域数比较方便

7、面向数据结构设计方法

(1)Jackson方法

看课本。即分析输入和输出的数据结构,具体到每一个循环级,思考怎样的操作能够转换该数据结构。

(2)Warnier方法

自行查阅

三、结构化系统实现


1、编码

(1)语言选择

程序设计语言分类:机器语言、汇编语言、高级语言

如何选择?

  • 系统用户要求:如果开发系统由用户维护,通常要求用熟悉的语言书写
  • 可以使用的编译程序:运行目标系统环境可提供编译程序限制可选用语言的范围
  • 可以得到的软件工具:有支持程序开发的软件工具可以利用。
  • 工程规模:规模庞大,现有语言不适用,设计实现供该工程项目使用程序设计语言
  • 程序员知识:如果和其他标准不矛盾,应选择程序员熟悉的语言
  • 软件可移植性要求:若目标系统在不同计算机上运行,选择可移植性好的语言
  • 软件的应用领域:选择语言时应充分考虑目标系统的应用范围。例如一些硬件设施中选择汇编或者C

(2)编码风格

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

  • 程序内部的文档

    • 恰当的描述符:命名规则一致、避免过长或过短、缩写规则一致、函数用大写字母开头单词
    • 适当注解:源程序中有效注解量在20%以上
      • 序言性注解:模块开始,描述模块功能、主要算法、接口特点、重要数据及开发简史(设计者、复审者及时间、修改日期)
      • 中间注解:插在程序中间,解释这段代码的必要性及功能。
    • 良好的视觉组织:空格、空行、缩进
  • 数据说明

    • 数据说明次序应标准化

      • 常量->简单变量->数组->公用数据块->文件
      • 整形->实型->字符->逻辑
    • 多个变量名在一个语句说明,按字母顺序排列。

    • 复杂数据结构用注解说明实现方法和特点。

  • 语句构造(简单)

    • 尽量避免复杂条件测试;
    • 尽量减少“非”条件测试;例如: if not(a>b)应该使用 if a<=b
    • 避免大量使用循环嵌套和条件嵌套;
    • 利用括号使表达式运算次序清晰直观。
    • 尽量少用go to语句
    • if、for、do、while、case、switch、default 等语句占一行,且if 、for 、do 、while 等语句的执行语句部分无论多少都要加括号{}
  • 输入输出

    • 1.对所有输入数据都进行检验,保证输入有效;
      2.检查输入项重要组合合法性;
      3.保持输入格式简单;
      4.使用数据结束标记,不要求用户指定数据数目;
      5.提示交互式输入请求,如可用选择或边界数值
      6.程序设计语言对格式有严格要求时,应保持输入格式一致;
      7.设计良好输出报表;
      8.给所有输出数据加标志
  • 效率(和存储容量);实际上效率控制需要在需求分析时就确定。

    • 程序运行时间
    • 存储器效率
    • 输入输出效率

2、软件测试

软件测试的目标

黑盒测试:如果知道产品应具有功能,可通过测试来检验是否每个功能都能正常使用。(忽略过程,关注输入和输出结果是否正确

白盒测试:如果知道产品内部工作过程可通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。()

测试准则:

(1)所有测试应能追溯到用户需求,测试的目的是发现错误,其中最严重的是不能满足用户需求的错误

(2)应尽早地和不断地进行软件测试。不应把软件测试仅看作是软件开发一独立阶段,应把它贯穿到软件开发各阶段中。需求分析等各种过程都需要测试的介入,早发现错误节省成本。

(3)充分注意测试中群集现象(Pareto原理)。测试后程序中残存错误数与程序中已发现错误数目成正比,80%错误与20%模块有关。

(4)测试应从小规模开始,逐步进行大规模测试。方便查找错误点

(5)不能做到穷举测试。想测试所有可能的输入是不可能的

(6)第三方测试原则。自己很难发现自己的错误

(1)白盒测试—逻辑覆盖

  • ①语句覆盖:选择测试数据,使被测程序中每个语句至少执行一次
    • 特点:只要语句都执行过就行。
  • ②判定覆盖:每个语句至少执行一次,每个判定的真假分支至少执行一次。
    • 特点:语句都执行过,且配个判定的真假情况都出现过。
  • ③每个语句至少执行一次,判定表达式每个条件取各种可能结果
    • 特点:语句都执行过,且每个每个小条件的真假情况都出现过。
  • ④判定/条件覆盖:取足够多测试数据,使判定表达式每个条件都取各种可能值,且每个判定表达式也都取到各种可能结果。
    • 注意:有时判定/条件覆盖不比判定覆盖更强
  • ⑤条件组合覆盖:选足够多的数据,是每个判定表达式中条件的各种组合都至少执行一次
    • 特点:一个判定中每个小条件的真假构成组合,将几个判定的组合构建构建在一起,保证每个判定中的各种组合都执行过一次。

注意:一定要明确“都执行过一次”的含义。例如判定A:只有一个条件,有两个条件所以有四种组合,判定B:也有两个条件所以有四种组合。而满足⑤的覆盖不是4*4而是4,因为一次执行A、B中的各一个语句,四次就能全部覆盖掉。

(2)白盒测试–控制结构测试

1、基本路径测试
  • ①使用程序复杂度中的McCabe方法导出流图、计算环形复杂度。

  • ②使用深度优先探索确定线性独立路径的基本集合

    • 独立路径:至少包含一条在定义该路径之前不曾用过的边。
    • 环形复杂度为独立路径基本集的上界。即环形复杂度是几,独立路径就有几条。
  • ③设计测试用例覆盖基本集合的路径

  • 例:计算不超过100个在规定值域内有效数的平均值;同时计算有效数字的综合和个数。用PDL描述的如图。

    设计符合各个路径的测试用例:

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

2、循环测试

  • (1)简单循环

    • ① 零次循环:从循环入口直接跳到循环出口。
    • ② 一次循环:查找循环初始值方面的错误。
    • ③ 二次循环:检查在多次循环时才能暴露的错误。
    • ④ m次循环:此时的m<n。
    • ⑤ 最大次数循环、比最大次数多一次循环、比最大次数少一次的循环。
  • (2)嵌套循环

    • ①从最内层循环开始,置所有其它层循环为最小值

    • ② 对最内层循环做简单循环的全部测试。

    • ③ 逐步外推,测试时保持所有外层循环变量取最小值,其它嵌套内层循环变量取“典型”值。

    • ④ 反复进行,直到所有各层循环测试完毕。

  • (3)连锁循环

    • 各个循环互相独立,可用与简单循环相同方法进行测试。
    • 几个循环不是互相独立,需要使用测试嵌套循环。
  • (4)非结构化循环:使用结构化程序设计方法重新设计

(3)黑盒测试

黑盒着重测:软件功能

黑盒发现错误类型:

(1)功能不正确或遗漏

(2)界面错误

(3)数据结构或外部数据库访问错误

(4)性能错误

(5)初始化或终止错误

1、等价类划分

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

有效等价类:合理,有意义输入数据构成集合。

无效等价类:不合理,无意义输入数据构成的集合。

等价类划分原则:

  • (1)输入条件规定范围,定义一有效等价类和两无效等价类
  • (2)输入条件是布尔量,一个有效等价类和一个无效等价类。
  • (3)规定输入数据一组值,,程序对每个输入值分别进行处理。每个输入值确立一有效等价类,针对这组值确立一个无效等价类。
    • 例:教工分房方案中,按教授、副教授、讲师、助教分别计分。 有效类4个;无效类1个。
  • (4)规定输入数据必须遵守规则,定义一有效等价类(符合规则)和若干无效等价类(从不同角度违反规则)
    • 例:Pascal语言规定“一个语句必须以分号‘;’结束”。 这时,可以确定一个有效等价类“以‘;’结束”,若干个无效等价类:以‘:’结束、以‘,’结束等。
  • (5)已划分等价类中各元素在程序中处理方式不同,将等价类进一步划分更小等价类。

确立测试用例:

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

(1)为每一等价类规定一唯一编号;

(2)设计一新测试用例,尽可能多覆盖尚未被覆盖有效等价类,重复,直到所有有效等价类被覆盖;

(3)设计一新测试用例,仅覆盖一尚未被覆盖无效等价类,重复,直到所有无效等价类被覆盖。

注意字眼:对于有效等价类:尽可能多、未覆盖;对于无效等价类:每个仅覆盖一个。

例:某城市电话号码由三部分组成

地区码:空白或3位数字

前缀:非“0’或‘1’开头的四位数字

后缀:4位数字

2、边界值分析

边界值分析是等价类划分补充。测试①恰好边界、②边界外一点、③边界内一点的数据

边界选择原则:

(1)输入条件规定了取值范围,则以该范围作为边界;

(2)输入条件规定值的个数,则以个数为边界;

(3)针对规格说明的每个输出条件,使用原则(1)和(2);

(4)如果规格说明给出的输入或输出域是有序集合(如有序表、顺序文件等),则选取集合中特定次序的元素作为边界,如第一个、最后一个元素等;

(5)如果程序中使用了一个内部数据结构,则应选择该结构的边界上的值,如数组、链表等;

(6)分析规格说明,找出其它可能边界条件。

例:某报表处理系统要求用户输入处理报表日期,日期在2001年1月至2005年12月,由年、月6位数字字符组成,前四位代表年,后两位代表月。用边界值分析法写出测试用例。

3、错误推测

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

例如:编写关于月份,测试用例很大程度就能猜到2月的易错点。

-----------------------本文结束 感谢阅读-----------------------
坚持原创技术分享,您的支持将鼓励我继续创作!恰饭^.^~