一.编码
编码和测试统称为系统实现。
1.目的:把模块的过程性描述翻译为用选定的程序设计语言书写的源程序(源代码)。
(真正交付给用户使用的,并不是源代码,而是经过编译链接生成的可执行的代码)
2.依据:编码的主要依据是概要设计和详细设计说明文档。
3.任务:理解概要设计和详细设计说明书,遵循编码原则和风格进行翻译,形成源代码。
4.机器语言:1011011000000000
5.汇编语言:机器指令助记符 MOV AX,BX
6.高级语言:与自然语言相近,面向用户的语言
7.语言选择标准:
系统用户要求:如果开发系统由用户维护,通常要求用熟悉的语言书写
可以使用的编译程序:运行目标系统环境可提供编译程序限制可选用语言的范围
可以得到的软件工具:有支持程序开发的软件工具可以利用。
工程规模:规模庞大,现有语言不适用,设计实现供该工程项目使用程序设计语言
程序员知识:如果和其他标准不矛盾,应选择程序员熟悉的语言
软件可移植性要求:若目标系统在不同计算机上运行,选择可移植性好的语言
软件的应用领域:选择语言时应充分考虑目标系统的应用范围。(充分利用不同语种各自的优势)
8.编码风格:逻辑简明清晰、易读易懂是重要标准
可遵循以下五方面规则:
程序内部的文档
(1)恰当的描述符:含义鲜明、变量名禁止取单个字符(如i、j),允许作局部循环变量、命名规则一致、避免过长或过短(建议英文)、缩写规则一致、函数用大写字母开头单词
(2)适当注解:源程序中有效注解量在20%以上:序言性注解、中间注解
(3)良好的视觉组织:空格、空行、缩进
数据说明
(1)数据说明次序应标准化(按数据结构或数据类型说明)
(2)多个变量名在一个语句说明,按字母顺序排列。
(3)复杂数据结构用注解说明实现方法和特点。
语句构造(简单)
(1)避免把多个语句写在同一行
(2)尽量避免复杂条件测试;
(3)尽量减少“非”条件测试;
(4)避免大量使用循环嵌套和条件嵌套;
(5)利用括号使表达式运算次序清晰直观
(6)尽量少用goto语句
(7)if、for、do、while、case、switch、default 等语句占一行,且if 、for 、do 、while 等语句的执行语句部分无论多少都要加括号{}
(注意:很多算法竞赛题的网站中,各种题主给出的答案总是忽略应该保留的花括号,这一点是不可取的,养成良好的编程习惯很重要)
(8)不将BOOL值TRUE和FALSE对应1和0。编程多数编程语言:false定义为0,非0值是true
输入输出
(1)对所有输入数据都进行检验,保证输入有效;
(2)检查输入项重要组合合法性;
(3)保持输入格式简单;
(4)使用数据结束标记,不要求用户指定数据数目;
(5)提示交互式输入请求,如可用选择或边界数值
(6)程序设计语言对格式有严格要求时,应保持输入格式一致;
(7)设计良好输出报表;
(8)给所有输出数据加标志
效率(和存储容量)——性能指标,从需求阶段定义
1.程序运行时间
(1)简化算术和逻辑表达式;
(2)嵌套循环,确定是否有语句可从内层往外移;
(3)尽量避免使用多维数组;
(4)尽量避免使用指针和复杂的表;
(5)使用执行时间短的算术运算;
(6)不要混合使用不同的数据类型;
(7)尽量使用整数运算和布尔表达式。
2.存储器效率
大中型计算机考虑操作系统页式调度特点,将程序功能合理分块,每个模块或一组密切相关程序体积与每页容量相匹配,减少页面调度。 微型计算机关键是程序简单性,选择生成较短目标代码且存储压缩性能优良的编译程序。
3.输入输出效率
(1)所有输入/输出都应有缓冲,减少通信的额外开销;
(2)对二级存储器(如磁盘)选用最简单访问方法;
(3)辅助存储器的输入/输出以信息组为单位进行;
(4)如“超高效”输入/输出很难被理解不采用。
二.软件测试
1.软件测试的目标:
2.黑盒测试(功能测试)
如果知道产品应具有功能,可通过测试来检验是否每个功能都能正常使用。
3.白盒测试
如果知道产品内部工作过程可通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。
4.测试准则
(1)所有测试应能追溯到用户需求,测试的目的是发现错误,其中最严重的是不能满足用户需求的错误。
(2)应尽早地和不断地进行软件测试。
不应把软件测试仅看作是软件开发一独立阶段,应把它贯穿到软件开发各阶段中。
(3)充分注意测试中群集现象(Pareto原理)。 测试后程序中残存错误数与程序中已发现错误数目成正比,80%错误与20%模块有关。
(4)测试应从小规模开始,逐步进行大规模测试。 单个模块,逐步集成。
(5)不能做到穷举测试。
例 穷举测试:程序所有可能执行路径都检查遍。
(6)第三方测试原则——从心理学角度考虑。(当局者迷旁观者清)
三.逻辑覆盖(白盒测试中设计测试用例的一种技术)
在测试阶段最关键的技术是设计测试用例,我们把输入的数据和预期的结果称为测试用例。
定义:测试数据在程序执行的过冲中所覆盖的路径。
1.语句覆盖:选择测试数据,使被测程序中每个语句至少执行一次
不关心判定的真假值等,是一种最弱的逻辑覆盖
2.判定覆盖:在语句全部覆盖的基础上,每个判定的真假分支至少执行一次。
(比语句覆盖强,但只覆盖一半路径)
3.条件覆盖:每个语句至少执行一次,判定表达式每个条件取各种可能结果
(即保证每个条件至少各取一次真假即可)
(注意:在满足条件覆盖的基础上,未必可以满足判定覆盖)
4.判定/条件覆盖
取足够多测试数据,使判定表达式每个条件都取各种可能值,且每个判定表达式也都取到各种可能结果。
(有时判定/条件覆盖不比判定覆盖更强)
5.条件组合覆盖(最强的覆盖)
选足够多的数据,使每个判定表达式中条件的各种组合都至少执行一次(实现全部组合一次)
(不同的判定之间的组合采用加法即可)
四.控制结构测试
1.常用技术:基本路径测试,循环测试
2.基本路径测试Tom McCabe提出的一种白盒测试技术
(1)根据过程设计结果画出相应流图
(流图只描述程序的控制流程,不描述数据的具体操作)
(2)计算流图的环形复杂度(寻找基本路径的指南)
箭头为控制流,节点为一条或者一组语句。(下图中本身围出来4个,但整个平面本身还是一个,因此是5个)。
(3)确定线性独立路径的基本集合
独立路径:至少包含一条在定义该路径之前不曾用过的边。
环形复杂度为独立路径基本集的上界。(即有几条路径就有几个)
(4)设计测试用例覆盖基本集合的路径
一些独立路径无法独立测试,程序的正常流程不能形成独立执行该路径所需的数据组合,这种情况下这些路径必须作为其他路径的一部分来测试。
3.循环测试
(1)简单循环
① 零次循环:从循环入口直接跳到循环出口。② 一次循环:查找循环初始值方面的错误。③ 二次循环:检查在多次循环时才能暴露的错误。④ m次循环:此时的m<n。⑤ 最大次数循环、比最大次数多一次循环、比最大次数少一次的循环。
(2)嵌套循环
①从最内层循环开始,置所有其它层循环为最小值 ② 对最内层循环做简单循环的全部测试。 ③ 逐步外推,测试时保持所有外层循环变量取最小值,其它嵌套内层循环变量取“典型”值。 ④ 反复进行,直到所有各层循环测试完毕。
(3)连锁循环
各个循环互相独立,可用与简单循环相同方法进行测试。
几个循环不是互相独立,需要使用测试嵌套循环。
(4)非结构化循环
使用结构化程序设计方法重新设计
五.黑盒测试(软件功能)
1.黑盒发现错误类型:
(1)功能不正确或遗漏(2)界面错误(3)数据结构或外部数据库访问错误(4)性能错误
(5)初始化或终止错误
2.常见黑盒测试技术:
(1)等价类划分(从数学的角度来说,等价类测试是完备的);
把程序的输入域划分成若干数据类,从每一数据类选取少数有代表性数据做为测试用例。
在各数据类中,各输入数据对揭露程序中的错误等效。
划分等价类
① 有效等价类:合理,有意义输入数据构成集合。
② 无效等价类:不合理,无意义输入数据构成的集合。
等价类划分原则:
- 输入条件规定范围,定义一有效等价类和两无效等价类。
- 输入条件是布尔量,一个有效等价类和一个无效等价类。
- 规定输入数据一组值,程序对每个输入值分别进行处理。每个输入值确立一有效等价类,针对这组值确立一个无效等价类。
例:教工分房方案中,按教授、副教授、讲师、助教分别计分。 有效类4个;无效类1个。
规定输入数据必须遵守规则
- 已划分等价类中各元素在程序中处理方式不同,将等价类进一步划分更小等价类。
确立测试用例
建立等价类表,列出所有划分出等价类:
为每一等价类规定一唯一编号;
设计一新测试用例,尽可能多覆盖尚未被覆盖有效等价类,重复,直到所有有效等价类被覆盖;
设计一新测试用例,仅覆盖一个尚未被覆盖无效等价类,重复,直到所有无效等价类被覆盖。(防止漏测)
(所谓等价类划分,本质上就是把具有合理性质的不同类别的数据划分为各种有效等价类,各种性质不合理的数据归纳为无效等价类)
(2)边界值分析——等价类划分补充(极值不出现问题则普通情况必定不出问题)
边界选择原则
(1)输入条件规定了取值范围,则以该范围作为边界;例:重量10-50kg的邮件……,选择边界值10、50、10.01、49.99、9.99及50.01。
(2)输入条件规定值的个数,则以个数为边界;例:“某输入文件可包含1至255个记录……”应选取1、255、0及256。
(3)针对规格说明的每个输出条件,使用原则(1)和(2);
(4)如果规格说明给出的输入或输出域是有序集合(如有序表、顺序文件等),则选取集合中特定次序的元素作为边界,如第一个、最后一个元素等;
(5)如果程序中使用了一个内部数据结构,则应选择该结构的边界上的值,如数组、链表等;
(6)分析规格说明,找出其它可能边界条件。
(3)错误推测
六.测试策略(将主系统划分为子系统开始测试)
1.单元测试:模块通过编译的语法检查后进入单元测试
- 模块接口 :数据是否正确进出模块。(例如通通过形参传递数据等等)
- 局部数据结构 :局部数据的说明、初始化、默认值是否有问题。
- 重要执行路径 :重要执行路径是否有错误计算、不正确比较或不适当控制流。
- 出错处理通路:(1)错误描述是否难于理解; (2)记下错误是否与实际遇到错误不同; (3)错误处理之前,错误条件已引起系统干预; (4)错误处理不正确; (5)描述错误信息不足以帮助确定错误位置;
- 边界条件:最重要,软件容易在边界上失效。
测试方法:
1.代码审查(人工) ——多种角色组成审查小组
先由编写人非正式进行,再由审查小组正式进行,可查30%到70%设计错误和编码错误。 (1)程序编写者讲解,审查小组审查; (2)预排演——代码走查,检验人员脑海里判断。
2.计算机测试
需要辅助模块模拟与被测模块相联模块,两种: (1) 驱动模块──相当被测模块主程序。接收测试数据,传送 给被测模块,再输出测试结果。 (2) 桩模块 ──存根模块。代替被测模块调用的子模块。
2.集成测试
- 测试与接口有关问题:
- 穿越接口数据是否丢失;
- 一模块功能是否对另一模块功能产生不利影响;
- 各子功能组合起来,能否达到预期的父功能;
- 全局数据结构是否有问题;
- 单个模块误差累积起来,是否会放大等。
测试方式:
1.非渐增式集成 (一次性集成):把所有模块一次组装进行测试。
(发现错误不易判断原因)
2.渐增集成将:模块逐步组装成较大系统
(1)自顶向下集成:
(2)自底向上集成:
(3)混合策略
改进的自顶向下测试方法 :基本用自顶向下方法,早期用自底向上测试关键模块。
混合法:软件结构上层模块用自顶向下,下层用自底向上。
3.回归测试 :重新执行已作过测试的某子集,保证变化没带来非预期副作用。
(避免因为集成后导致部分模块功能出现问题)
回归测试集:
(1)检测软件全部功能的代表性测试用例;
(2)专门针对可能受修改影响的软件功能附加测试;
(3)针对被修改过软件功能测试
4.系统测试使软件和其它系统元素(硬件、数据库等)结合测试
用于系统测试的测试类型:
(1)恢复测试(强制软件出现故障,观察软件是否有自动恢复的本领)
以不同方式强制软件出现故障,检测软件能否恰当完成恢复
自动恢复: 检测重新初始化、数据恢复、重新启动等是否正确。人工干预恢复: 检测平均恢复时间是否在允许范围内。
(2)安全性测试 :突破软件安全保护机构的安全保密措施,检验系统预防机制的漏洞。
测试者扮演试图攻击系统角色:通过外部手段获取密码;通过客户软件攻击系统;控制系统使其他人无法访问;引发系统错误,期望在系统恢复中侵入系统等。
(3)强度测试
检验系统能力最高达到实际限度, 让系统处于资源异常数量、异常频率、异常批量条件下测试系统承受能力。 一般比平常限度高5-10倍的限度做测试用例。
(4)性能测试
软件运行性能与性能要求比较,检验是否达到性能要求规格
5.确认测试(验收测试)
系统测试后,客户再验收测试。
确认测试以需求规格说明书为测试基础,采用黑盒法。
- α测试:用户对即将面市软件产品(称α版本)进行测试,开发者坐在用户旁边,随时记下错误情况和使用中问题,是受控环境下测试。
目的: 评价软件功能、可使用性、可靠性、性能、界面。
- β测试:多个用户在实际使用环境下进行的测试 用户与公司签定支持产品预发行合同,使用产品,并返回错误信息。是在开发者无法控制的环境下进行的软件现场应用。
目的: 产品的支持性。
七.调试
软件调试是在进行了成功的测试之后才开始的工作。它与软件测试不同,调试的任务是进一步诊断和改正程序中潜在的错误。
1.调试活动:① 确定程序错误的性质和位置。② 修改程序,排除错误。
2.调试步骤:
(1)从错误现场入手,确定程序出错位置;
(2)找错误的内在原因;
(3)找到则排除错误,回归测试。
(4)否则,加测试用例证明猜测原因。
3.调试方法
强行排错:
(1)将内存内容打印出来分析。
(2)程序特定部位设置打印语句。 各关键变量改变部位、重要分支部位等,监视重要变量变化。
(3)自动调试工具。 程序语言调试功能或专门交互式调试工具,不必修改程序。如设置断点,观察程序断点处状态,包括变量、表达式值等。
回溯法排错(小程序常用): 确定最先发现“症状”位置。人工沿程序控制流程向回追踪源代码,直到找到错误根源或确定错误产生范围。
原因排除法:对分查找法、归纳法、演绎法
(1)对分查找法如已知每个变量在程序内若干关键点正确值,用赋值或输入语句在程序中点附近“注入”正确值,运行程序检查输出。正确,错误原因在程序上半部分;反之,在程序后半部分。反复使用,将程序出错范围缩小到容易诊断的程度。
(2)归纳法调试归纳法是一种从特殊推断一般的逻辑方法。归纳法调试的想法是:从一些线索(错误征兆)着手,通过分析它们之间的关系来找出错误。(3W1H表)
(3) 演绎法排错 演绎法是从一般原理或前提出发,经过排除和精化的过程来推导出结论的逻辑方法。根据已有测试用例,设想所有可能出错原因;逐个排除不正确的;验证余下假设确是出错原因。
八.软件可靠性(发现错误的终极目标是为了保证软件可靠性)
可靠性:程序在给定时间间隔及环境条件下,按规格说明书的规定,成功运行的概率。(时间间隔)
可用性:给定的时间点,按规格说明书规定,成功运行概率。(时间点)