文章目录
- 软件测试基础
 - 1.1软件测试概述
 - 什么是软件测试
 - 什么是软件需求说明书
 - 软件测试的原则
 - 测试用例的设计
 - 测试用例设计的基本原则
 - 软件测试分类
 - 软件缺陷的定义
 
- 2.1软件开发模型
 - 软件开发模型概述
 - 大爆炸模型(边写边改)
 - 软件开发生命周期模型--螺旋模型
 - 软件开发模型--敏捷模型
 
- 2.2软件测试模型
 - V模型
 - W模型
 - H模型
 - X模型
 - 综合策略
 
- 2.3软件测试流程
 - 熟悉需求
 - 制定测试计划
 - 什么时候开始指定测试计划
 - 使用和维护测试计划
 - 软件测试计划基本结构
 - 正确认识测试计划
 - 什么是测试用例
 - 设计测试用例简单格式
 - 开发测试脚本
 - 搭建测试环境
 - 实施测试
 - 测试评估与总结
 - 测试总结报告定义
 
- 3.1黑盒-等价类划分
 - 如何使用等价类划分法
 - 等价类测试步骤
 
- 3.2黑盒-边界值测试
 - 3.3黑盒-组合测试法
 - 目的额
 - 方法
 - 组合测试的输入数据要求
 - 组合强度(以下表为例)
 
- 3.4黑盒-决策表
 - 基本原理
 - 决策表的组成
 - 决策表适用的范围
 
- 3.5黑盒-因果图
 - 概述
 - 四种基本关系
 - 因果图中的约束
 
- 3.6黑盒-场景法
 - 定义
 
- 3.7黑盒-状态转换法
 - 定义
 - 目标
 - 状态图的使用步骤
 
- 3.8黑盒-错误推断法
 - 什么是错误推断法
 - 什么时候使用错误推断法
 - 优点
 - 缺点
 
- 其他测试方法
 - 4.1静态白盒测试(用于单元测试和集成测试)
 - 白盒测试关注的对象
 - 白盒和黑盒测试比较
 - 优势
 - 不足和弊端
 - 什么是静态白盒测试
 - 静态测试特点
 - 静态白盒测试应该怎样做
 - 代码审查的关注点
 - 评审结果
 - 计算环复杂度
 
- 4.2怎样代码审查
 - 4.3白盒-基于判定的覆盖
 - 语句覆盖
 - 判定覆盖
 - 条件覆盖
 - 条件判定覆盖
 - 条件组合覆盖
 - 修正的判定/条件覆盖
 
- 4.4白盒-基于路径的测试
 - 独立路径的抽取
 
- 4.5白盒-基于循环的测试
 - 对单个循环节点的测试
 - 串联循环节点的测试
 - 非结构化循环结构的测试
 
- 4.6白盒-基于变量的测试
 - 变量常见的3种缺陷
 - 定义节点
 - 使用节点
 - 定义/使用节点对
 - 定义/使用路径
 - 定义/清除路径
 - 测试步骤
 
- 5.1单元测试
 - 什么是单元测试
 - 单元选取的原则
 - 良好的单元测试需要遵循的AIR原则
 - 驱动和桩模块的设计
 
- 5.2单元测试工具 JUnit的使用
 - 常用注解
 - 断言
 - 实例
 
- 5.3集成测试
 - 集成测试的策略
 
- 5.4系统测试
 - 6.1测试过程管理
 - 6.2测试中的其他知识
 - 6.3CMM模型
 
软件测试基础
1.1软件测试概述
什么是软件测试
使用人工或自动手段来运行测试某个系统的全过程,目的在于检验其是否满足规定的需要,或是弄清楚预期结果与实际结果之间的差别
什么是软件需求说明书
软件需求说明书的编制是为了使用户和软件开发者双方对该软件的初始规定有一个共同的理解, 使之成为整个开发工作的基础。包含硬件、功能、性能、输入输出、接口需求、警示信息、保密安全、数据与数据库、文档和法规的要求等等
软件测试的原则
1、尽早地和及时地进行测试,从需求阶段开始介入
- 软件测试应贯穿软件生命周期
 - 不同阶段引入的缺陷对于软件的影响不同
 
2、测试前应该准备好测试数据和与之对应的预期结果这两部分
3、测试输入数据应包括合理的输入条件和不合理的输入条件
4、程序提交测试后,应当由专门的测试人员进行测试
5、严格执行测试计划,排除测试的随意性
6、测试用例的预期结果应做全面的检查
7、充分注意测试当中的集群现象
8、保存测试计划、测试用例、出错统计和最终分析报告,为维护工作提供充分的资料
9、不追求 ZERO BUG 而保证 GOOD ENOUGH
10、缺陷具有免疫性
测试用例的设计
- 正常数据
 - 错误数据
 - 边界数据
 
测试用例设计的基本原则
- 满足覆盖度的前提下,数量越少越好
 - 典型性越高越好
 - 对缺陷的定位性越强越好
 
软件测试分类
- 从是否关系内部结构分 
- 黑盒测试
 - 白盒测试
 
 - 从是否运行被测程序角度 
- 动态测试
 - 静态测试
 
 - 从执行时是否需要人工干预角度 
- 手工测试
 - 自动化测试
 
 - 从软件开发的过程的角度 
- 单元测试
 - 集成测试
 - 系统测试
 - 验收测试
 
 - 从测试实施组织的角度划分 
- 开发方测试
 - 用户测试
 - 第三方测试
 
 
软件缺陷的定义
- 软件未达到需求规格说明书中指明的功能
 - 软件出现了需求规格说明书中指明不应出现的错误
 - 软件功能超出需求规格说明书中指明的范围
 - 软件未达到需求规格说明书中虽未指出但应达到的目标
 - 软件测试员认为软件难以理解、不易使用、运行速度缓慢,或者最终用户认为不好
 
2.1软件开发模型
软件开发模型概述
软件开发模型是软件开发的全部过程、活动、任务和管理的结构框架。它给出了软件开发活动各阶段之间的关系
大爆炸模型(边写边改)
- 优点:思路简单,通常可能是开发者的“突发奇想”
 - 缺点:开发工程是非工程化的,随意性大,结果不可预知
 - 测试:开发任务完成后,修复困难
 
瀑布模型(适用于操作系统、数据库管理系统)

-  
优点:
- 如同瀑布流水,逐级下落
 - 将软件生存周期各活动规定为依线性顺序联接的若干阶段的模型
 - 易理解,阶段明显,强调需求分析,明确测试阶段,提供了一套模板
 - 文档驱动
 
 -  
缺点:
- 线性严格–成果晚出–风险大
 - 阶段固定–反复&迭代不适合–灵活性差
 - 单次需求–需求变更多–适应性差
 - eee测试滞后–缺陷晚查–代价大
 
 
软件开发生命周期模型–螺旋模型

四个象限代表的
- 制定计划:确定软件目标,选定实施方案,弄清项目开发的限制条件
 - 风险分析:分析评估所选方案,考虑如何识别和消除风险
 - 实施工程:实施软件开发和验证
 - 客户评估:评价开发工作,提出修正建议,制定下一步计划
 
优点:严格的全过程风险分析管理;强调各开发阶段的质量;提供机会评估项目是否有价值继续下去。
软件开发模型–敏捷模型
- 敏捷模型以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发
 - 在敏捷开发中,软件项目在构建初期被切分为多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征
 

2.2软件测试模型
V模型
动态测试行为应与开发行为对应,每个测试阶段的基础是对应开发阶段的提交物,并通过低层测试确保源代码正确,通过高层测试保证整个系统满足用户需求
局限性:测试滞后

W模型
静态测试和动态测试行为伴随整个开发阶段,并与开发行为对应,有助于早期发现缺陷、了解项目难度、评估测试风险,并加快项目进度,降低项目成本

V&V:Verification & Verify
P&D:Plan & Design
局限性:
- 将软件开发看成需求分析、设计和编码等一系列串行的活动
 - 开发、测试之间保持着线性的前后关系,无法支持迭代的开发模型,无法支持变更调整
 - 未体现测试流程的完整性
 
H模型
测试流程应独立于其他流程,且应保持自身的完整性,即测试是一个独立的流程,与其他流程并发进行,且其本身的测试准备和执行活动是分离的,不同测试活动可按某个次序先后进行,也可能是重复的,只要测试准备工作完成,就可以开始测试执行

X模型
清晰地体现了单元测试→集成测试→系统测试的过程,该模型还能处理开发中包括交接、频繁重复的集成等工作,更加贴合实际的项目开发流程

综合策略
- 宏观上以W模型为基本框架,将软件开发和测试作为两个并行的过程,测试伴随整个开发过程
 - 微观上对每个测试阶段则以H模型为指导,进行独立测试,即只要满足测试执行条件就可以进行独立的测试,并反复迭代测试,直至达到预定目标
 - 当项目小组的开发过程中存在诸多不确定因素时(如需求的变更、对缺陷的修复等),则可利用X模型,针对每个相对独立的系统组成部分,进行相互分离的编码和测试,经多次交接后集成为最终的版本
 - 对于软件企业而言,则应以软件测试成熟度模型(TMM)为指导,努力建立规范的软件测试过程
 
2.3软件测试流程
熟悉需求
- 阅读相关说明
 - 阅读相关资料
 - 提出疑问
 - 站咋用户的角度进行需求评审
 
制定测试计划
软件测试计划就是在软件测试工作正式实施之前明确测试的对象,并且通过对资源、时间、风险、测试范围和预算等方面的综合分析和规划,保证有效的实施软件测试
什么时候开始指定测试计划
- 软件测试计划应当尽早的指定,需求说明说确定之后进行
 - 软件测试计划在测试活动中处于中心位置
 - 它设定了测试准备工作和执行测试的必备条件,同时形成了测试过程质量保证的基础
 
使用和维护测试计划
- 使用过程中要对测试计划进行必要的监测 
- 测试计划要经过评审
 - 测试项目要按照计划执行
 - 测试计划是否需要调整或修改
 
 
软件测试计划基本结构
正确认识测试计划
- 谁是测试计划的最终用户 
- 测试计划的最终用户一般是研发团队
 - 测试计划作为产品提交给用户(特殊需求、军方、外包测试用户)
 
 
什么是测试用例
为实施测试而向被测试系统提供的输入数据、操作或各种环境设置以及期望结果等信息的一个特定集合
格式

设计测试用例简单格式
开发测试脚本
搭建测试环境
- 开发环境
 - 测试环境
 - 正数环境
 
实施测试
- 执行测试用例
 - 提交BUG
 - 回归测试
 
测试评估与总结
测试总结报告定义
3.1黑盒-等价类划分
- 有效等价类 
- 设计一个新用例,使它能够尽量多覆盖尚未覆盖的有效等价类。重复该步骤,知道所有有效等价类均被用例覆盖
 
 - 无效等价类 
- 设计一个新用例,使它仅覆盖一个尚未覆盖的无效等价类,重复该步骤,直到所有的无效等价类均被用例所覆盖
 
 
如何使用等价类划分法
-  
按输入区间划分
如果输入条件规定了取值范围,则可以划分为一个有效等价类,小于下限、或大于上限的所有数据分别构成两个无效等价类
 -  
按数值集合划分
如果输入条件规定了输入值的集合,或者规定了“必须如何”的条件,则满足必须条件的数据构成一个有效等价类,其他数据构成一个无效等价类
 -  
按离散数值划分
如果规定了输入数据的一组值,并且系统要对每个输入值分别进行处理,则可以为每一个输入值确立一个有效等价类,此外还要针对这组值确立一个无效等价类,它是所有不允许的输入值的集合
 -  
按限定条件或规则划分
如果规定了输入数据必须遵守的规则,则可以确定一个有效等价类以及若干个不同角度违反规则的无效等价类
 -  
按布尔量取值划分
如果某个输入条件只有两种取值,是/否,则可以定义一个有效等价类和一个无效等价类,或者定义两个有效等价类
 -  
细分等价类
当发现已划分的等价类中各个元素在程序中的处理方式不同,需要对等价类进一步划分为更小的等价类
 
等价类测试步骤
- 划分等价类
 - 细划等价类
 - 建立等价类表
 - 编写测试用例
 
3.2黑盒-边界值测试
定义:在被测对象的边界及边界附近设计测试用例
边界值测试是一种最基本、最简单的黑盒测试方法,通常可作为等价类测试的补充
边界值分析法设计的测试用例要比等价类划分法的代表性更广,发现错误的能力也更强。
【例题】




3.3黑盒-组合测试法
目的额
为组合爆炸情况提供一种相对合理的解决方案,在保证错误检出率的前提下采用较少的测试用例
方法
通过被测软件的参数和参数可取的值,按照一定的组合策略来规划测试
组合测试的输入数据要求
- 组合的参数的取值范围必须是可离散的
 - 对于取值范围连续的参数或者存在过多的取值,有必要先使用其他测试设计技术,如等价类划分、边界值等,将一个很大的取值范围减少为一个可控的子集
 
组合强度(以下表为例)
| 单选项 | 可选值 | 
|---|---|
| 目的地 | 北京、上海、广州 | 
| 舱位 | 头等舱、公务舱、经济舱 | 
| 座位 | 靠过道、靠窗 | 
常见的组合强度有:
-  
单一选择
-  
被测试软件中所有参数取值范围的任意可能取值至少被一个测试用例覆盖
测试用例编号 目的地 舱位 座位 预期结果 1 北京 头等舱 靠过道 预订成功 2 上海 公务舱 靠窗 预订成功 3 广州 经济舱 靠过道 预订成功  
 -  
 -  
基本选择
-  
被测软件中,对于任意一个参数的N个取值,存在N条测试用例覆盖这N个取值,且其他参数的取值相同
 -  
如给出一个基本选择:上海、经济舱、靠窗
测试用例编号 目的地 舱位 座位 预期结果 1 上海 经济舱 靠窗 预订成功 2 北京 经济舱 靠窗 预订成功 3 广州 经济舱 靠窗 预订成功 4 上海 头等舱 靠窗 预订成功 5 上海 公务舱 靠窗 预订成功 6 上海 经济舱 靠过道 预订成功  
 -  
 -  
成对组合
-  
被测软件中任意两个参数,他们取值范围的任意一对有效值至少被一个测试用例覆盖
- 组合如下:
 
测试覆盖编号 测试覆盖内容 测试覆盖编号 测试覆盖内容 测试覆盖编号 测试覆盖内容 1 北京,头等舱 8 广州,公务舱 15 广州,靠窗 2 北京,公务舱 9 广州,经济舱 16 头等舱,靠过道 3 北京,经济舱 10 北京,靠过道 17 头等舱,靠窗 4 上海,头等舱 11 北京,靠窗 18 公务舱,靠过道 5 上海,公务舱 12 上海,靠过道 19 公务舱,靠窗 6 上海,经济舱 13 上海,靠窗 20 经济舱,靠过道 7 广州,头等舱 14 广州,靠过道 21 经济舱,靠窗 设计测试用例覆盖上面所有组合
测试用例编号 目的地 舱位 座位 预期结果 测试覆盖项 1 北京 头等舱 靠过道 预订成功 1,10,16 2 北京 公务舱 靠窗 预订成功 2,11,19 3 北京 经济舱 靠过道 预订成功 3,10,20 4 上海 头等舱 靠过道 预订成功 4,12,16 5 上海 公务舱 靠窗 预订成功 5,13,19 6 上海 经济舱 靠过道 预订成功 6,12,20 7 广州 头等舱 靠窗 预订成功 7,15,17 8 广州 公务舱 靠过道 预订成功 8,14,18 9 广州 经济舱 靠窗 预订成功 9,15,21  
 -  
 -  
全组合
- 被测试软件中所有参数取值范围的任意有效取值的组合至少被一个测试用例所覆盖
 
 -  
K强度组合
- 在组合强度要求为K的组合中(简称为K强度),任意K个参数取值范围的任意有效值的组合至少被一个测试用例覆盖
 - 当K=1时,K强度组合就算单一选择;当K=2时,K强度组合就等同于成对组合;而当K等于所有参数数量时,K强度组合等同于全组合
 
 
3.4黑盒-决策表
基本原理
也称判定表法,是分析和表达多种逻辑条件下执行不同操作情况的工具。
在一些数据处理当中,某些操作的实施依赖于与多个逻辑条件的组合,即对不同逻辑条件的组合值,分别执行不同的操作,决策表适合于处理这种问题
决策表的组成
- 条件桩:列出了问题的所有条件(输入区)
 - 动作桩:列出了问题规定可能采取的操作,这些操作的排列顺序没有约束(输出区)
 - 条件项:列出针对于它左列条件的取值。在所有可能情况下的真假值(输入取值区)
 - 动作项:列出在条件项的各种取值情况下应该采取的动作(输出取值区)
 
【例题】
每年的6月18日是淘宝的购物狂欢节,也是消费者们购物的好时机。在这个节日里,淘宝会推出各种促销活动,其中最受欢迎的莫过于满减活动
- 满减优惠券:根据不同商家的策略和商品类别,满减金额会有所不同,用户可以自行在商品页领券。
 
商家会设定不同的满减优惠券,满200减20、满300元减50元、满500元减100元。
2.订单金额
订单金额要达到指定的满减金额才能享受满减优惠。
- 定金:
 
用户可以选择在指定时间内支付部分商品款项(10%或20%的定金),如果10%定金,在已经满减后的基础上打9折,如果20%定金,在已经满减后的基础上打8折。
根据以上需求,请使用决策表设计用例
一、写出条件桩、条件项、动作桩、动作项
二、画出完整的决策表
三、简化决策表
四、设计测试用例
【解答】
条件桩为:满减优惠券、订单金额是否达到满减金额、定金
条件项为:领取满200-20优惠券、领取满300-50优惠券、领取满500-100优惠券、达到满减金额、未达到满减金额、支付10%定金、支付20%定金
动作桩为:满减、打折
动作项为:满减20、满减50、满减100、打九折、打八折、不满减、不打折




决策表适用的范围
- 规格说明书以决策表的形式给出,或很容易转化为决策表
 - 条件的排序顺序不会影响执行哪些操作
 - 规则的排列顺序不会影响执行哪些操作
 - 当某规则的条件已经满足,并确定要执行的操作后,不必检验别的规则
 - 如果某一规则要执行多个操作,这些操作的执行顺序无关紧要
 
3.5黑盒-因果图
概述
因果图法是从需求中找出因(输入条件)和果(输出或程序状态的改变),通过因果图转化为判定表
输入和输出之间的关系
输入条件之间的关系(组合关系、约束关系等)
四种基本关系
-  
恒等
-  
原因与结果之间一对一的关系。若原因出现,则结果出现;若原因不出现,则结果不出现

 
 -  
 -  
非
-  
原因与结果之间否定关系。若原因出现,则结果不出现;若原因不出现,则结果出现

 
 -  
 -  
或
- 表示几个原因若有一个出现,则结果出现;只有当这几个原因都不出现时,结果才不出现
 
 

-  
与
-  
表示几个原因若都出现,则结果才会出现;若几个原因有一个不出现,结果就不会出现

 
 -  
 
因果图中的约束
对于输入条件有E、I、O、R四种约束,对于输出条件的约束只有M约束
- E约束(异/互斥):a和b两个原因中最多有一个可能成立,即a和b不能同时成立
 

-  
I约束(或/包含):a、b、c中至少有一个必须成立

 -  
O约束(唯一):a和b必须有一个且仅有一个成立
 

- R约束(要求):当a出现时,b也必须出现
 

- M约束(屏蔽):若结果a为1,则结果b强制为0
 

【例题】
某软件规格说明书包含这样的要求:第一列字符必须是A或B,第二列字符必须是一个数字,在此情况下进行文件的修改,但如果第一列字符不正确,则给出信息L;如果第二列字符不是数字,则给出信息M
1)分析原因和结果
| 原因 | 结果 | 
|---|---|
| c1:第一个字符是A | e1:给出信息L | 
| c2:第一个字符是B | e2:修改文件 | 
| c3:第二个字符是一个数字 | e3:给出信息M | 
2)画出因果图

3)在因果图上表明约束或限制条件

4)转换为决策表

5)转换成测试用例

3.6黑盒-场景法
定义
通过分析不同事件的触发顺序和处理结果,构建各个事件流,并基于这些事件的触发控制业务流程,形成多个不同场景,最终基于场景设计测试用例
-  
基本流
从系统的某个初始状态开始,经一系列状态变化后到达终止状态的过程中最主要的一个业务流程
 -  
备选流
以基本流为基础,在经过基本流上每个判定节点(包括条件判定和循环判定)处满足不同的触发条件,而导致的其他事件流
 
画流程图
构建场景
注意事项
- 最少的场景数等于事件流的总数,基本流与备选流的总数
 - 有且唯一有一个场景仅包含基本流
 - 对应某个备选流,至少应该有一个场景覆盖
 
3.7黑盒-状态转换法
定义
是一种基于产品规格分析,对系统的每个状态及与状态相关的函数进行测试,通过不同的状态验证程序的逻辑流程
任何一个系统,如果对同一个输入,根据不同的状态,可以得到不同的输出,就算一个有限状态系统
目标
设计测试用例达到对系统状态的覆盖,状态-条件组合的覆盖以及状态迁移路径的覆盖
状态图的使用步骤
1、根据需求,理解关键字段,获得主要的状态
2、绘制状态迁移图
3、画出状态迁移树
4、抽取测试用例规则
3.8黑盒-错误推断法
什么是错误推断法
是基于经验和直觉推测程序中可能出现的各种错误和容易发生错误的特殊情况,将其列为清单,然后有针对性的设计测试用例。这些根据经验总结的错误清单通过不断积累、修正和分享,可以帮助测试人员发现很多潜在的软件缺陷。
什么时候使用错误推断法
先采用其他方法设计测试用例,然后再利用错误推测法补充用例
优点
- 能够充分发挥测试人员的直觉和经验;通过问题积累、总结和分享,做到集思广益和不断提高测试效果;使用方便,能够快速切入和解决问题。
 
缺点
- 难以统计测试的覆盖率;可能对大量未知的问题区域未做测试,无法保证测试的充分性;带有主观性,缺乏系统严格、有章可循的方法,因此难以复制;难以支持自动化测试。
 
其他测试方法
- 随机测试(猴子测试) 
- 一种没有书面测试用例、记录期望结果、检查列表、脚本或指令的的测试,根据测试者的经验或软件进行功能和性能抽查
 
 - 探索式测试
 
4.1静态白盒测试(用于单元测试和集成测试)
白盒测试关注的对象
- 源代码 
- 阅读源代码,检查代码规范性,并对照函数功能查找代码的逻辑缺陷,内存管理缺陷、数据定义和使用缺陷等
 
 - 程序结构 
- 使用与程序设计相关的图表,找到程序设计的缺陷,或评价程序的执行效率
 
 
白盒和黑盒测试比较
- 黑盒测试:功能级别
 - 白盒测试:函数级别
 
优势
- 针对性强,便于快速定位缺陷
 - 在函数级别开始测试工作,缺陷修复成本低
 - 有助于了解测试覆盖程度
 - 有助于代码优化和缺陷预防
 
不足和弊端
- 对测试人员要求高 
- 测试人员需要具备一定的编程经验
 - 白盒测试工程师需要具备广博的知识
 
 - 成本高 
- 白盒测试需要的时间长
 
 
什么是静态白盒测试
对系统静态检查,这种检查通常不需要运行被测软件,而是直接对软件形式和结构进行分析
静态测试特点
- 静态测试不需要运行程序,不必设计测试用例和结果分析
 - 静态测试可以人工执行,充分发挥人的思维优势
 - 静态测试不需要特别的条件,容易展开
 - 静态测试对测试人员的要求较高,需要具有编程经验
 
静态白盒测试应该怎样做
-  
代码检查
- 同行评审 
- 早期无法提供可运行的对象,无法执行测试
 - 特定类型的缺陷,通过测试无法发现
 
 - 同行评审的核心:缺陷预防
 - 目的:发现缺陷,改进开发过程
 

 - 同行评审 
 
代码审查的关注点
- 功能性
 - 可读性
 - 可测性
 - 可维护性
 - 性能
 - 多线程
 - 安全性
 
评审结果
- 正常
 - 延期
 - 取消
 
-  
静态结构分析
-  
函数调用关系图
- 根节点需要优先测试
 - 叶子节点需要优先测试
 - 接口数量多的节点需要优先测试
 
 -  
函数控制流图
 

 -  
 
结点:用圆表示。一个节点代表一条或多条顺序执行语句。程序流程图中的一个顺序的处理框程序和一个菱形判定框,可以映射成流图中的一个结点。
边:用箭头线表示。边代表控制流,一条边必须终止于一个结点,即使这个结点不代表任何语句
注意:如果判定包含复合条件,生成控制流图时,应当把复合条件分解为若干个简单条件,每个简单条件对应流图中的一个结点
计算环复杂度
-  
直接观察法
- 封闭区域+1
 
 -  
公式计算法
- V(G) = e - n + 2
 - e代表边数
 - n代表节点数
 - 单入口和单出口
 
 -  
判定节点法(只适用于if else的分支)
-  
V(G) = p + 1(p代表独立判定节点的数目)
 -  
遇到switch语句要转换(一条和其他,其他再细分为一条和其他)

 
 -  
 
- 代码质量度量
 
4.2怎样代码审查

-  
编码风格
- 命名风格 
- 不以下划线或美元符号开头或结束
 - 类名UpperCameICase
 - 方法名,参数名,成员变量,局部变量都统一适用LowerCameICase
 - 常量命名适用全大写,单词间用下划线分隔
 - 包名统一适用小写
 - 禁止拼音命名
 - 禁止不规范的缩写
 
 - 常量定义 
- 禁止未定义的常量
 - 长整型赋值需要适用大写L后缀
 - 变量值可穷尽,考虑适用枚举
 
 - 代码格式 
- 采用四个空格缩进,禁止使用tab字符
 - 单行字符数限制不超过120个
 - 换行符使用unix格式
 
 - OOP规约 
- 静态方法/变量使用类名访问
 - 复写方法增加@Override
 - 禁止过时方法/类的使用
 - 包装类型比较使用equals方法
 
 - 分支控制 
- switch中,每个case必须使用,continue/break/return终止或者注释说明到哪个case终止
 - switch需要对字符串判空
 - 分支逻辑使用大括号
 
 - 注释 
- 类/方法注释使用javadoc规范
 - 方法内部单行注释,使用//在需要被注释的语句上方单起一行
 - 无用代码删除,而不是注释
 
 
 - 命名风格 
 -  
命名规范
- 使用有意义的名字
 - 范围越大,命名越长
 - 范围越小,命名越短
 - 避免使用非约定的缩写
 - 使用一种自然语言来命名,如英语
 - 使用对应领域的专业名称,例如算法名称等
 - 不好命名,考虑类、方法职责过多,是否需要拆分重构
 - 一致性
 
 -  
功能性
- 代码是否复合用户意图
 - 输入输出、流程是否正确
 - 边界是否考虑并处理妥当
 - 是否有高并发的安全问题
 
 -  
测试覆盖
 -  
复杂度
- 复杂度高导致的问题 
- 可读性降低
 - 可维护性降低
 - 缺陷率高
 - 模块内聚性低
 
 - 复杂度V(G)
 - 复杂度优化 
- 方法抽取
 - 反向表达
 - 单一职责
 - 使用多态
 
 
 - 复杂度高导致的问题 
 -  
注释
- 对外、公共的接口
 - 模块、系统描述
 - 宁缺毋滥
 
 -  
审查设计
- 提升系统稳健性
 - 提升可读性/可维护性
 - 提升可扩展性
 
 -  
安全性
- 安全性低有什么问题 
- 数据容易泄露
 - 程序运行异常
 - 资源消耗异常
 
 
 - 安全性低有什么问题 
 
4.3白盒-基于判定的覆盖
语句覆盖
保证程序的每一条可执行语句至少执行一次

判定覆盖
使得程序中每个判定节点至少都获得一次“真值”和“假值”,每一个真假分支至少被执行一次,又被成为分支覆盖。是一个比“语句覆盖”稍强的测试标准
条件覆盖
设计若干测试用例,使得每个判定中每个条件的可能取值至少满足一次,和判定覆盖没有强度关系

条件判定覆盖
设计若干测试用例,使得判定中所有条件可能取值至少执行一次,同时,使得所有判定的可能至少执行一次
但因为实际上某些条件掩盖了另一些条件,导致有些错误不一定能检查出来
【例题】针对coverage1() 根据判定条件覆盖设计用例 ,完成以下表格,需要考虑条件屏蔽
public void coverage1( int i, int j) {int x = 0;int y = 0;if (i > 0 && j > 0) {y = y + 1;} else {if (i > -5 || j > -5)y = y - 1;elsex = x - 2;}System.out.println("x=" + x + ";y=" + y);}
 

条件组合覆盖
设计若干测试用例,使得判定条件中的各种组合都至少执行一次
修正的判定/条件覆盖
在满足判定条件覆盖的基础上,每个简单判定条件都应独立地影响到整个判定表达式的取值,实质是利用简单判定条件的独立影响性来消除测试用例的冗余

4.4白盒-基于路径的测试
路径:程序从起始执行到程序结束经过的所有节点和连接线
独立路径
- 从全路径集合中抽取一组线性无关的路径
 - 是指至少引入一个新处理语句或一条新判断的程序通路
 
独立路径的抽取
- 1、画程序控制流图
 - 2、计算环复杂度(环复杂度是测试用例条数的上限)
 - 3、确定独立路径集合
 - 4、准备测试用例
 
注意:路径测试不一定满足条件覆盖,一定满足判定覆盖
【例题】
针对coverage2()设计测试用例,满足基本路径覆盖。
要求:
(1)、(10分)画出控制流图
(2)、(10分)计算V(G)
(3)、(30分)写出独立路径,并设计测试用例
public void coverage2(int tag, int i, int j) {int x = 0;int y = 0;while (tag > 0) {x = x + 1;if (i > 0 && j > 0) {y = y + 1;tag = 0;} else {if (i > -5 || j > -5)y = y - 1;elsex = x - 2;tag--;}}System.out.println("x=" + x + ";y=" + y);}
 


4.5白盒-基于循环的测试
对单个循环节点的测试
void SampleFunc4(int iteration){for (int i = 1; i < iteration; i++){System.out.println(i);}
}
 
测试点如下
- 循环0次(不进入循环)
 - 循环1次
 - 循环2次
 - 循环正常次数(通常是最大次数的一半)
 - 循环n-1次
 - 循环n次
 

循环的初始化
- 初始值设置是否正确
 
循环的迭代
-  
语句执行过程
 -  
增量的变化
 -  
涉及到的变量的取值
 -  
误差累积
 -  
内存压力
 -  
continue,break语句是否导致循环过程中强制跳过部分语句不执行
 
循环的终止
- 循环的终止条件
 - 退出循环的条件
 
串联循环节点的测试
public ststic void test(){int i, j;for(i = 1; i < 10; i++){for(j = 1; j <= 10; j++){System.out.print(i + "*" + j + "=" + i * j + " ");}System.out.print("\n");}
}
 
-  
先测试最内层循环体,然后逐步外推,直至测试到最外层的循环体
 -  
测试每层循环体时,仍根据单个循环体的测试原则进行测试
 -  
考虑四种特殊组合
- 内层最小循环次数,外层最小循环次数组合,计算结果
 - 内层最小循环次数,外层最大循环次数组合,计算结果
 - 内层最大循环次数,外层最小循环次数,计算结果
 - 内层最大循环次数,外层最大循环次数,计算结果
 
 
非结构化循环结构的测试
- 首先:建议修改代码
 - 其次:如果不能修改代码,则先对单次循环体进行测试;兼顾嵌套循环条件下对循环次数的多种特殊组合
 
public ststic void test(){int i, j;for(i = 1; i < 10; i++){for(j = 1; j <= i; j++){System.out.print(i + "*" + j + "=" + i * j + " ");}System.out.print("\n");}
}
 
4.6白盒-基于变量的测试
变量常见的3种缺陷
- 变量在使用前从未定义过(在编译时,会有提示,不需人工查找)
 - 变量被定义,但从未使用过
 - 变量在使用前,被多次定义 
- 寻找这种错误的过程,是一种静态分析的过程,不需要设计测试用例
 
 
定义节点
- 若被测变量v的值在某条包含该变量的语句n处发生改变,则称该语句是关于变量v的定义节点,记做DEF(v,n)
 - 输入语句、赋值语句(对该变量赋值)、循环控制语句(循环变量)都是定义节点
 
使用节点
- 若被测变量v的值在某条包含该变量的语句n处被使用,则称该语句是关于变量v的使用节点,记做USE(v,n)
 - 输出语句、赋值语句(变量v对其他变量的赋值)、条件语句、循环控制语句都是使用节点
 
定义/使用节点对
- 由被测变量v的一对定义节点和使用节点构成的一个二元组称为该变量的定义/使用节点对
 
定义/使用路径
- 从被测变量v的一个定义节点开始执行,到该变量的某个使用节点结束的一条路径称为该变量的一条定义/使用路径,记做du-path
 
定义/清除路径
- 若被测变量v的一条定义/使用路径中不包含该变量的其他定义节点,则该路径称为定义清除路径,记做dc-path
 
测试步骤
- 确定需要重点测试的变量V
 - 确定变量V的所有定义节点和使用节点
 - 确定变量V的所有定义/使用节点对
 - 对V的重要定义/使用路径
 - 判断每条定义/使用路径是否为高风险路径 
- 一条定义/使用路径,若该路径不是定义清楚路径,则认为该路径是高风险路径,应重点测试
 
 
【举例】对变量的测试分析举例
 public static void test() {
1  int a = 5;
2  int b = 20;
3  while(b >= 9) {
4       if(a >=2) {
5            b = a * a;
6            a = a - 1;
7         }
8     }
9    System.out.println(a);
10  System.out.println(b);
} 
| 变量 | 定义节点 | 使用节点 | 路径(开始、结束)节点 | 是定义-清除路径吗 | 
|---|---|---|---|---|
| a | 1,6 | 4,5,6,9 | (1,4)(1,5)(1,6)(1,9) (6,4)(6,5)(6,6)(6,9)  | 是,是,是,否,是,是,是,是 | 
| b | 2,5 | 3,10 | (2,3)(2,10)(5,3)(5,10) | 是,否,是,是 | 
5.1单元测试
什么是单元测试
- 是指对软件中的最小可测试单元或基本组成单元进行检查和验证
 
单元选取的原则
- 对于面向过程的开发语言来说,单元常指一个函数或子函数
 - 对于面向对象的开发语言来说,单元一般指一个类
 - 图形化软件中,单元常指一个窗口或一个菜单
 
良好的单元测试需要遵循的AIR原则
- A:Automatic(自动化)
 - I:Independent(独立性)
 - R:Repeatable(可重复)
 
驱动和桩模块的设计
驱动模块
是模拟被测单元的上级模块,用于接收测试数据、启动被测模块和输出结果
桩模块
是模拟被测单元所调用的模块。有时,需要使用子模块的接口,才能做少量数据操作,并验证和打印入口处的信息,然后返回。桩模块不包含原模块的所有细节
驱动模块功能要求
- 利用已有的测试用例,接收测试输入数据
 - 将测试数据传递给被测单元
 - 打印和输出测试用例的相关结果,判断测试是通过还是失败(断言)
 - 通过测试日志文件记录测试过程,便于后续数据保存和分析(Log4j)
 
桩模块功能要求
- 在特定条件下完成原单元的基本功能
 - 能够被正确调用
 - 有返回值
 - 不包含原单元的所有细节
 
5.2单元测试工具 JUnit的使用
常用注解

断言

实例
要求使用JUnit5,对于下列代码设计若干条测试用例,进行单元测试,要求实现语句覆盖100%。
public class MaxDay {int GetMaxDay(int year, int month) {int maxday = 0;if (month >= 1 && month <= 12) {if (month == 2) {if (year % 4 == 0) {if (year % 100 == 0) {if (year % 400 == 0)maxday = 29;elsemaxday = 28;} elsemaxday = 29;} elsemaxday = 28;} else if (month == 4 || month == 6 || month == 9 || month == 11)maxday = 30;elsemaxday = 31;}return maxday;}
 
步骤
画控制流图
写测试用例
编辑CSV文档
package homework;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;class MaxDayTest {@ParameterizedTest@CsvFileSource(resources = "./MonthAndYear.csv",numLinesToSkip = 1)void testGetMaxDay(int month,int year,int except){MaxDay maxDay = new MaxDay();int result = maxDay.GetMaxDay(month,year);Assertions.assertEquals(except,result,"抱歉,您没通过此条测试用例");}}
 
5.3集成测试
集成测试就是在单元测试的基础上,将所有已通过单元测试的模块按照概要设计的要求组装为子系统或系统,并进行测试的过程,目的是确保各单元模块组合在一起后能够按既定意图协作运行,并确保增量的行为正确
集成测试的策略
-  
大爆炸集成
- 将所有经过单元测试的模块一次性组装到被测系统中进行测试,完全不考虑模块之间的依赖性和可能的风险
 - 优点:测试规模小
 - 缺点:违反了测试从小范围到大范围展开的原则,难以定位问题
 - 适用场景:稳定的软件版本,或涉及模块和接口数量不多的情况下
 
 -  
自顶向下集成
- 从主控模块开始,按照系统程序结构,沿着控制层次从上而下,逐渐将各模块组装起来 
- 深度优先策略
 - 广度优先策略
 
 - 优点:早期实现并验证主要功能
 - 缺点:桩模块开发和维护工作量大,难以发现底层模块复杂算法的缺陷,随着测试进行会越来越复杂
 
 - 从主控模块开始,按照系统程序结构,沿着控制层次从上而下,逐渐将各模块组装起来 
 -  
自底向上集成
- 从底层模块开始,按照调用图的结构,从下而上,逐层将各模块组装起来
 - 优点: 
- 有助于早期发现底层模块中的复杂算法的缺陷;
 - 单个测试用例包含多个模块,可从整体上降低测试用例规模
 - 多个集成测试可并行展开,确保测试工作进度
 
 - 不足 
- 驱动模块的开发和维护工作量较大
 - 难以早期发现上层模块中有关逻辑和控制方面的缺陷
 - 直至加入最后一个模块才能看到整个系统框架,难以早期发现时序问题和资源竞争问题
 
 
 -  
混合集成(三明治集成)
- 将自顶向下和自底向上集成的方法结合起来的集成策略,在调用图上按照一定的策略,分别自顶向下和自底向上展开集成,并在字树上进行大爆炸集成
 - 优势 
- 能尽早地发现错误
 - 测试效率高
 
 - 不足 
- 中间地目标层可能得不到充分的测试
 - 需要同时开发桩和驱动模块,这部分工作量比较大
 - 需在子树上进行大爆炸集成,一旦发现缺陷,涉及的接口数量较多,增加了缺陷定位难度
 
 
 
| 项目 | 测试用例数目 | 桩模块 | 驱动模块 | 缺陷定位 | 并行测试 | 系统概貌 | 
|---|---|---|---|---|---|---|
| 大爆炸 | 少 | 不需要 | 不需要 | 非常困难 | N/A | 早期 | 
| 自顶向下 | 较多 | 需要 | 不需要 | 较容易 | 困难 | 早期 | 
| 自底向上 | 较多 | 不需要 | 需要 | 较容易 | 可以 | 较晚 | 
| 混合集成 | 较多 | 需要 | 需要 | 较困难 | 可以 | 早期 | 
5.4系统测试
-  
功能测试
- 主要针对系统的功能需求展开测试,以确定被测系统是否满足用户的功能使用要求
 - 是测试系统中最基本的测试
 
 -  
性能测试
- 对软件的运行性能指标进行测试,判断系统集成之后在实际的使用环境下能否稳定、可靠的运行 
- 时间性能:软件的一个具体事务的响应时间
 - 空间性能:软件运行时消耗的系统资源
 
 - 常规性能测试 
- 软件在正常的软、硬件环境下运行,不向其施加任何压力的性能测试
 
 - 压力测试 
- 持续不断地给被测系统增加压力,直至被测系统被压垮,以确定系统能承受的最大压力
 - 压力测试应注意累计效应问题
 
 - 负载测试 
- 通常是让被测系统在其能忍受的压力极限范围内(或临界状态下)连续运行,来测试系统的稳定性
 - 目的是找到被测系统的处理极限,位系统调优提供依据
 - 负载测试侧重于压力持续的时间,压力测试则更加强调施加压力的大小
 
 - 可靠性测试 
- 在给被测系统加载一定业务压力的情况下,使系统运行一段时间,测试系统是否稳定
 
 - 大数据量测试 
- 针对某些系统存储、传输、统计、查询业务进行大量数据量的独立数据量测试
 - 与压力测试、负载测试、疲劳测试等并发测试相结合的极限状态下的综合数据量测试
 
 
 - 对软件的运行性能指标进行测试,判断系统集成之后在实际的使用环境下能否稳定、可靠的运行 
 -  
安全性测试
- 测试内容 
- 资源
 - 风险
 - 安全性控制
 
 
 - 测试内容 
 -  
兼容性测试
- 硬件兼容性测试
 - 软件兼容性测试
 - 数据兼容性测试
 
 -  
用户界面测试
规范性、灵活性、正确性、直观性、舒适性、实用性、一致性、帮助、独特性、多窗口应用与系统资源
 -  
安装与卸载测试
 -  
易用性测试
 
6.1测试过程管理
6.2测试中的其他知识
- 验收测试(测试工作以用户为主) 
- α测试:开发者坐在用户旁边,这是在开发者受控的环境下进行的测试
 - β测试:在开发者无法控制的环境下进行的测试
 
 - 回归测试 
- 对新版本测试时,对旧版本重新测试
 
 - 冒烟测试 
- 选取系统中重要功能,重要使用流程等进行测试
 
 - 测试需求
 - 持续性集成
 - 测试报告文档的书写
 
6.3CMM模型
- 第一级:初始级
 - 第二级:可重复级
 - 第三级:定义级
 - 第四级:定量管理级
 - 第五级:(不断)优化级