软件测试方法和技术实践笔记(二)——单元测试基础
单元测试基础
单元测试的定义
定义
单元测试(又称为模块测试,Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作
时机
单元测试和编码同步进行,但在测试驱动开发(TDD)中,强调测试在先,编码在后
单元测试一般由开发人员完成,QA人员辅助
目标
输入和输出对应正确
内部数据保持完整性,内部数据的形式、内容、相互关系
边界值正确处理
满足特定的逻辑覆盖
单元测试的必要性
测试越早介入越好
分析、设计、编码阶段 缺陷比例 10%、40%、50%
软件生命周期阶段,越往后,bug产生的成本越高
编码过程中,每写1000行代码会犯几十个错误
编程和编译结束后,每1000行代码中大约残留2-6个bug
寻找和解决BUG的代价占总体开发时间的30%-60%
为什么程序员不愿做单元测试:
-
不愿做 没有做单元测试习惯,没有意愿
-
没时间 项目周期短,基于敏捷开发的节奏越来越快 写单元测试要花很多时间
-
做不了 代码耦合性高,开展困难
-
做不好 要达到较高的代码覆盖率很困难
程序员心理:
-
写单元测试导致不能按时完成任务,推迟项目进度
-
单元测试价值不高,完全是浪费时间
长期来看,相比没有单元测试的项目,有单元测试的项目在开发周期中更省时间
-
业务逻辑简单,不值得写单元测试
需求会变化,需求文档、代码注释往往不会更新。单元测试可以记录需求变更
代码编写者去写单元测试比其他人更完善、更准确
代码维护
集成测试
-
不知道怎么编写单元测试
- 为所有类编写单元测试
- 学会使用断言
- 最大化测试覆盖率
- 避免重复的测试代码
- 不依赖测试方法的执行顺序
-
项目前期尽量写单元测试,越到后期越失控
-
项目没有要求,所以不写
代码如何测
评价标准:代码覆盖率
代码覆盖的步骤:
- 源代码转为流程图,流程图可以直观的描述代码逻辑
- 分析流程图,选择需要覆盖的代码
- 确定测试数据,生成测试用例
白盒测试方法:
- 语句(statement)覆盖
- 分支(branch)覆盖/判定(decision)覆盖
- 条件(condition)覆盖
- 判定/条件覆盖
- 条件组合覆盖
语句覆盖
语句覆盖 = (被执行的语句数量/总的语句数量)* 100%
达到100%的语句覆盖很困难
- 不可达代码
- 处理错误代码(处理异常)
- 小概率事件
分支/判定覆盖
忽略了表达式内的条件,不能发现每个条件的错误
条件覆盖
确保每个条件取True和False各一次,可以检查每个原子条件,不能保证所有判断分支都覆盖
判定/条件覆盖
判定条件中的所有条件可能至少执行一次取值,同时,所有判定的可能结果至少执行一次。判定覆盖和条件覆盖的组合
条件组合覆盖
使得每个判定的所有可能的条件取值组合至少执行一次
可满足分支覆盖,也满足语句覆盖
覆盖率
基本准则:
- 覆盖率部署目的,只是一种手段
- 不可能针对所有的覆盖率去测试
- 只考虑一种覆盖标准不恰当
- 不要追求绝对100%覆盖率
其它准则:
- 使用最少的测试来达到最大的覆盖
- 要考虑测试质量,兼顾效益、成本
- 软件变化需要更新相应的覆盖
代码评审
通过阅读代码来检查软件是否符合编码规范,是否符合代码质量标准
评审内容:
- 编码规范问题:命名不规范、magic number、System.out…
- 代码结构问题:重复代码、巨大的方法和类、分层不当
- 工具、框架使用不当:Spring、Hibernate、AJAX
- 实现问题:错误验证、异常处理、事务划分、线程、性能、安全、代码过于复杂、代码可读性不佳、扩展性不好
- 测试问题:测试覆盖率不高、可测试性不好
代码评审中的问题:
- 低级问题 命名规范和代码风格
- 中级问题 可重用性问题、控制结构和逻辑问题
- 高级问题 性能、安全、冗余、功能问题、错误处理、可测量性问题
检查点:
路径测试:
- 误解或用错了算符优先级
- 混合类型运算
- 变量初值错
- 精度不够
- 表达式符号错误
- 其它
数据结构测试:
- 变量无初值
- 不适合或者不相容的类型说明
- 变量初始化或者默认值有错
- 不正确的变量名或从未被使用过
- 出现上溢或下溢地址异常
- 其它
模块接口测试:
- 输入的实际参数与形式参数是否一致
- 调用其它模块的实际参数和被调模块的形参是否一致
- 全程变量的定义在各模块是否一致
- 外部输入、输出
- 文件、缓冲区、错误处理
- 其它
单元边界条件测试:
- 普通合法数据的处理
- 普通非法数据的处理
- 边界值内合法边界数据的处理
- 边界值外非法边界数据的处理
- 其它
单元容错测试:
- 输出的出错信息难以理解
- 记录的错误和实际不相符
- 异常处理不当
- 未提供足够的定位出错信息
- 其它