当前课程知识点:软件工程 > 第3章 单元测试 > 3.1 单元测试概述 > 讲课视频
在现实开发中
缺乏软件工程经验的开发人员
往往在编码完成之后
就迫不及待地进行软件集成工作
表面上看这样做
可以很快地看到实际系统
但是由于缺少应有的单元测试
系统中经常充满了各种Bug
也会造成故障难以定位
修复困难等问题
这样就会增加额外的时间和成本
这幅图展示了编码
和测试的不同阶段
引入和发现缺陷的情况
以及修复它们的成本
开发人员在编写代码的同时
不可避免地会引入缺陷
图中的数据告诉我们
大多数的缺陷
是在编码的初期产生的
修复它们的成本在初期也比较低
越往后拖
增长的幅度就越大
单元测试是软件开发过程中
重要的质量保证活动
它的质量在很大程度上
影响着软件产品的最终质量
单元是构造系统的基础
这就好比是长城的城墙
如果每块砖的质量不过关
那么建造的城墙就不会坚固
编写代码也是如此
底层代码出现问题
就会牵扯到上层代码
它的修改也可能会导致
其他代码的一连串改动
从而影响整个产品的质量
只有打造坚实的基石
才能保证上层建筑的坚固
单元测试
是对软件中的最小可测试单元
进行检查和验证
它要测试和验证程序代码中
每一项功能的正确性
为后续的开发提供支持
编写单元测试
可以使开发人员
从调用者的角度
进行观察和思考
这样编写的程序
更易于调用和测试
也可以将程序的缺陷降低到最小
单元测试也是一种文档化的行为
测试用力可以说明函数或者类
是如何使用的
自动化的单元测试
也有助于进行回归测试
我们在前面讲过
产品的质量
是在构建的过程中形成的
开发人员必须对自己的代码负责
单元测试
就是对所开发代码质量的
一个基本的承诺
对于程序员来说
编程不仅仅意味着编写代码
还要完成单元测试
在现实中我们发现
那些代码质量最好
开发速度最快的程序员
也是单位测试做得最好的程序员
单元测试的内容
主要包括以下方面
第一模块接口
主要是检查参数表
调用子模块的参数
全程数据 文件IO等内容
第二 局部数据结构
主要检查数据类型说明
初始化 缺省值等方面的问题
还要查清全程数据对模块的影响
第三 边界条件
要特别注意数据流
或者控制流中
刚好等于 大于
或者小于边界值的情况
因为这些地方非常容易出错
第四 独立路径
主要是对模块中重要的执行路径
进行测试
通过对基本执行路径
和循环进行测试
可以发现大量的路径错误
第五 出错处理
这一部分
是检查模块的错误处理功能
是否存在错误或者缺陷
如果对模块运行时间有要求的话
还要专门进行关键路径测试
以确定最坏情况下
和平均意义下
影响模块运行时间的因素
通过单元测试
我们可以保证单元模块的质量
这样为整个的系统
打造了坚实的基础
单元测试包括快速 独立
可重复 自我验证
和及时五个原则
单元测试必须要快
太慢的话就没有人再愿意
频繁地运行它
单元测试也要相互独立
否则一个测试没有通过
就会导致一连串的失败
很难定位问题
单元测试是要能够重复执行的
而且结果也是可以重现的
单元测试执行结束之后
应该由布尔输出
来显示是否通过
而不应该通过人工的方式来确认
开发人员
应该及时编写单元测试代码
最好是在开发单元代码之前
来完成
单元测试过程主要包括以下步骤
首先
我们要找出程序中
潜在的最大问题区
来确定哪些部分需要做单元测试 其次针对要做的测试
来编写相应的测试用例
之后编写单元测试代码
执行单元测试 产生测试结果
如果测试结果满足了
测试质量的要求
那么整个测试结束
否则还要根据结果和测试的要求
来修改和增加新的测试用例
再进一步地进行测试
衡量测试质量的指标
一般有测试通过率
和测试覆盖率
测试通过率是在测试过程中
测试用例的通过比例
单元测试一般都是要达到100%
测试覆盖率
是用来衡量测试的完整性
它可以告诉我们
测试是否充分
以及测试的弱点在哪里
我们可以通过增加测试用例
来提高覆盖率
进而提升测试质量
单元测试一般用代码覆盖率
来衡量
代码覆盖率大致达到70%
到80%就可以了
过高的覆盖率可能会造成
测试成本的大大增加
代码覆盖率的度量
有多种不同的方式
包括语句覆盖 条件覆盖
和路径覆盖等
我们将在白盒测试方法一讲中
进行详细地介绍
单元测试
包括静态测试和动态测试
两种类型
其中静态测试是通过人工分析
或者程序正确性证明的方式
来确认程序的正确性
而动态测试则是通过动态的分析
和运行程序的方式
来检查和确认
程序中是否存在问题
对于测试用例设计来说
有黑盒测试和白盒测试两种技术
黑盒测试也称功能测试
它是把测试对象
看成是一个黑盒子
只是根据需求规格说明
来设计有代表性的测试输入
再通过测试执行的输出结果
来检查程序的功能
是不是符合规格说明
白盒测试也称结构测试
它允许测试人员
根据程序内部的结构
来设计测试用例
对于程序的逻辑路径等进行测试
一个单元模块并不是独立存在的
模块之间
总会存在相互调用的关系
比如说一个被测模块
通常会被上层的模块来调用
同时它又调用多个下层的模块
那么在单元测试的时候
如何来保证被测模块是独立的
并且能够构成一个可运行的程序呢
在这种情况下
我们需要开发驱动模块和桩模块
他们将被测模块进行隔离
并帮助完成单元测试
其中驱动模块
用于替代上层的调用模块
它去调用被测模块
并且判断被测模块的返回值
是否与测试用例的预期结果相符
桩模块
则用于替代下层的调用模块
它要模拟地返回
所替代模块的各种可能的返回值
单元测试一般需要借助工具
来编写测试代码
目前最流行的
是针对不同编程语言的
系列Unit框架
我们在后面
单元测试工具这一讲中
将介绍Python语言的PyUnit
其他的框架
大家可以在以后的开发中
自己学习和使用。 xUnit测试
一般适合单个函数
或类的测试
尤其是纯函数
或者接口级别的测试
对于一些复杂场景就很难适用
但是这些场景
往往才是测试的重点
也是难点所在
以分布式系统为例
类和函数级别的单元测试
是远远不够的
这种系统
主要是测试进程之间的交互
例如
一个进程收到客户请求
应该如何处理
然后转发给其他进程等
另外分布式系统的测试
通常更关注一些异常的路径
那么这种复杂的场景
应该如何进行单元测试
Mock方法
可以帮助我们解决
前面所说的那些复杂场景中
遇到的难题
这种测试是在测试过程中
对于某些不容易构造
或者不容易获取的对象
用一个虚拟的对象
也就是Mock对象来创建
以便进行测试
这里列出了一些Mock测试
适合的场景
现在我们举例说明
Mock测试的基本方法
春节期间
很多同学可能都玩过接龙红包
它是通过猜金额
这样一个小游戏的方式
来实现朋友之间的互动
并且可以领取春节红包
在这个程序中
GiftMoney这个类
允许设定红包的金额
和上下限
并且将所猜的金额和设定金额
进行比较
由于数据是存放在数据库中
所以这一个类
就需要调用
数据库存取访问的方法
那么这种情况下
应该如何进行测试
刚才红包的问题可以抽象成
ClaassA对ClassB的访问
在进行Mock测试时
需要把程序之间的直接调用
转换成通过接口进行访问
也就是说
先抽象出一个接口InterfaceB
ClassA直接调用它
ClassB来具体地实现它
然后在使用Mock对象
来模拟所调用的对象及其行为
这时被测模块
并不知道它所引用的
究竟是真实对象
还是Mock对象
通过这样的方式
可以把被测模块
和所依赖的模块进行隔离
从而实现复杂场景下的单元测试
下面我们再来思考一个
微信抢票应用的例子
开发人员编写的抢票程序
是通过直接调用系统函数
来获得当前的系统时间
在单元测试的时候
我们需要设定不同的时间
进行抢票测试
如果我们要利用真实的系统时间
来测试的话
就只能苦苦等到实际设定的时间
才能进行检验
显然这是一个很笨的做法
那么如果使用Mock的方法
进行测试
应该如何来重构这个程序呢
对于这个问题
请大家结合
刚才讲解的Mock测试内容
在课下进行思考和讨论
-1.1 软件无处不在
--讲课视频
-1.2 软件的本质特性
--讲授视频
-1.3 软件工程的产生与发展
--讲授视频
-1.4 软件工程的基本概念
--讲授视频
-1.5 软件质量实现
--讲授视频
-1.6 业界人士谈软件工程
-测验题--作业
-讨论题
--讨论题
-作业题
--第一张 作业题
-2.1 编程过程与规范
--讲课视频
-2.2 良好的编程实践
--讲课视频
-2.3 Python集成开发环境
--讲课视频
-2.4 代码静态检查
--讲课视频
-2.5 代码性能分析
--讲课视频
-2.6 结对编程实践
--讲课视频
-2.7 刘贺谈软件工程
--讲课视频
--讨论
-测验题--作业
-作业题
--第二章 作业题
-3.1 单元测试概述
--讲课视频
-3.2 黑盒测试方法
--黑盒测试方法
-3.3 白盒测试方法
--基本概念
--代码覆盖标准
--基本路径测试
-3.4 单元测试工具
--单元测试工具
--html
-测验题--作业
-作业题
--第三章 作业题
--作业题附件
-4.1 软件过程
--讲课视频
-4.2 软件过程模型
--讲课视频
-4.3 敏捷开发过程
--讲课视频
-4.4 微软公司开发过程
--邹欣经理自我介绍
--微软开发过程之一
--微软开发过程之二
-测验题--作业
-5.1 团队组织与管理
--讲课视频
-5.2 项目沟通管理
--讲课视频
-5.3 软件项目计划
--讲课视频
-5.4 软件项目估算
--讲课视频
-测验题--作业
-讨论题
--讨论
-6.1 敏捷开发之Scrum
-- 敏捷开发之Scrum
--html
-6.2 用户故事与估算
--讲课视频
-6.3 团队协作工具Tower
-6.4 配置管理
--讲课视频
-6.5 配置管理工具Git
--讲课视频
-测验题--作业
-作业题--作业
-7.1 需求工程师
--讲课视频
-7.2 需求定义
--讲课视频
-7.3 需求的类型
--讲课视频
--讲课视频(2)
-7.4 需求工程过程
--讲课视频
-7.5 需求的主要来源
--讲课视频
-7.6 需求获取技术
--讲课视频
--讲课视频二
--讲课视频三
-7.7 撰写需求文档
--讲课视频
-测验题--作业
-讨论题
--讨论
-8.1 用例建模概念
--讲课视频
-8.2 用例建模过程
--讲课视频
-8.3 用例建模精讲
--讲课视频
-8.4 建模工具介绍
--讲课视频
-8.5 微信抢票应用案例
--讲课视频
-测验题--作业
-讨论题
--讨论
-9.1 面向对象分析
--讲课视频
-9.2 CRC卡片分拣法
--讲课视频-1
--讲课视频-2
-9.3 面向对象设计
--讲课视频-1
--讲课视频-2
-9.4 类图建模
--讲课视频-1
--讲课视频-2
-第9章 面向对象分析与设计--测验题
-讨论题
--讨论
-10.1 顺序图概念
--讲课视频
-10.2 顺序图建模
--讲课视频
-10.3 顺序图风格
--讲义视频
-10.4 状态建模
--讲课视频
-10.5 状态图
--讲课视频
-10.6 状态图精讲
--讲义视频
-测验题--作业
-讨论题
--讨论
-11.1 软件体系结构概念
--讲授视频
-11.2 软件设计原则
--讲授视频
-11.3 软件体系结构风格(一)
--讲授视频
-11.4 软件体系结构风格(二)
--讲授视频
-11.5 软件体系结构风格(三)
--讲授视频
-11.6 软件设计过程
--讲授视频
-11.7 Web系统架构设计
--讲授视频
-11.8 数据库选择策略
--讲授视频
-测验题--作业
-作业题
--html
--html
--html
-作业题--作业
-12.1 交互设计概述
--讲授视频
-12.2 交互设计目标
--讲授视频
-12.3 GUI设计原则
--讲课视频
-12.4 KLM效率模型
--Video
-12.5 Fitts定律
--讲授视频
-12.6 交互设计过程
--讲授视频
-测验题--作业
-13.1 软件测试概念
--讲课视频
-13.2 软件测试类型
--讲课视频
-13.3 软件功能测试
--讲课视频
-13.4 软件性能测试
--讲课视频
-测验题--作业
-14.1 软件部署与交付
--讲课视频
-14.2 软件演化与维护
--讲课视频
-测验题--作业
-第一部分:基础知识
-第二部分:编程与测试(选做)