软件测试之-单元测试
1、单元测试概念
1)单元测试是对软件基本组成单元进行的测试,如函数(fuction或procedure)或一个类的方法(method)。这里,基本单元不一定是指一个具体的函数(fuction或procedure)或一个类的方法(method),在具体实现时,也可能对应的是多个程序文件中的一组函数。
2)在软件系统中,单元也具有一些基本属性,如:明确的功能、规格定义、明确的与其他部分的接口定义等,可清晰的与同一程序的其他单元划分开来。
2、单元测试的目的
1)单元测试的目的在于发现各模板内部可能存在的各种错误,主要是基于白盒测试。
2)软件产品不仅仅包含代码,还包含各种文档,因此测试应从三方面考虑:
a.针对文档的测试;
b.针对代码的测试;
c.针对文档和代码是否一致的测试。
3)单元测试阶段,对应的文档时详细设计说明书,对应的代码是单元代码,因此单元测试的目的主要有三方面:
a.验证单元代码和详细设计文档的一致性;
b.跟踪详细设计文档中设计的实现,发现详细设计文档中存在的错误;
c.发现在编码过程中引入的错误(编码过程中引入的错误包含两类:和设计不符引入的错误;和设计相符但由于编码出现疏漏导致错误),这里其实是针对文档和代码是否一致的测试。
3、单元测试中常见错误(单元测试关注重点)
单元的常见错误一般出现在5个方面:代码的稳定、易读、规范、易维护、专业。
因此,单元测试的关注的重点有5点:单元接口、局部数据结构、边界条件、独立路径、出错处理,下列一一介绍。
1)单元接口
接口实际上就是输入输出对应关系的集合,如果数据不能正确的输入和输出,就谈不上进行其他测试,单元接口处常见错误:
a.被测单元的输入输出参数在个数、属性、顺序上和详细设计中的描述不一致;
b.修改了只做输入用的形式参数,可能会导致数据的错误修改;
c.约束条件通过形式参数来传送,导致函数间的控制耦合增大(耦合是指两个实体相互依赖于对方的一个度量)。
2)局部数据结构
在单元工作过程中,必须测试单元内部的数据能否保持完整性,包括内部数据的内容、形式及内部关系不发生错误。
对于局部数据结构,应该在单元测试中注意发现以下几类错误:
a.不正确或不一致的数据类型说明;
b.使用尚未赋值或尚未初始化的变量;
c.错误的初始值或错误的缺省值;
d.变量名拼写或书写错误。
3)独立路径
对基本执行路径和循环进行测试会发现大量的错误,常见的错误有:
a.运算的优先次序不正确或误解了运算的优先次序;
b.运算的方式错误;
c.不同数据类型的比较;
d.关系表达式中不正确的变量和比较符;
e.“差1错”。即不正确的多循环或少循环一次;
f.错误的或不可能的循环终止条件;
g.当遇到发散的迭代时不能终止的循环;
h.不适当地修改了循环变量等。
4)出错处理
比较完善的单元设计要求能预见出错条件,并设置适当的出错处理,以便在出错时,能对出错程序重新作安排,保证其逻辑上的正确性,出错处理模块常见的错误或缺陷有:
a.出错的描述难以理解;
b.出错的描述不足以对错误定位和确定出错的原因(这个错误由系统的安全级别来定);
c.现实的错误与实际的错误不符;
d.对错误条件的处理不正确;
e.在对错误惊醒处理之前,错误条件已经引起系统的干预等。
5)边界条件
边界上出现错误是比较常见的,单元测试时,应当仔细的测试为限制数据处理而设置的边界条件。
需要注意与边界有关的数据类型如数值、字符、位置、数量、尺寸等,还需注意这些边界的首个、最后一个、最大值、最小值等特征,常见错误出现情况:
a.在n次循环的第n次,取最大最小值时容易发生错误;
b.特别要注意数据流,控制流中刚好等于、大于、小于确定的比较值时出现错误的可能性。
4、单元测试环境
在单元测试时,由于单元本身不是一个独立的程序,一个完整的可运行的软件系统并未构成,所以需要设置一些辅助测试单元,辅助测试单元有两种:驱动单元和桩单元。
1)驱动单元(Driver)
用来模拟被测试单元的上层单元,相当于被测函数的主程序,它接收测试数据,将相关数据传送到被测单元,启动被测单元,最后再输出实测结果。当被测单元能完成相关功能时,也可以不要驱动单元。
驱动单元,主要完成以下几个步骤
a.接受测试数据,包含测试用例的输入和预期输入;
b.把测试用例输入传送给要测试的单元,驱动被测单元执行;
c.将被测单元的实际输出和预期输出进行比较,得到测试结果;
d.将测试结果输出到指定位置。
2)桩单元(Stub)
指用来代替被测单元工作过程中调用的子单元,桩单元的功能是从测试角度模拟被测单元所调用的其他单元,桩单元需要针对不同的输入,返回不同的期望值,模拟不同的功能。如果被测单元为底层函数吗,则不需要设计桩单元。
桩单元的类型:系统函数、自定义函数。
桩单元模拟的单元可能是自定义函数:这些自定义函数可能尚未编写完成,为了测试被测单元,需要构造桩单元来替代他们;或者可能存在错误,会影响测试结果,给分析被测单元造成困难,因此需要构造正确无误的桩单元来达到隔离的目的。
3)构造单元的测试环境的主要工作
a.构造最小运行调度系统,即驱动单元,用以模拟被测单元的上一级单元;
b.模拟实现单元接口,即单元函数需调用的其他函数接口,即桩单元;
c.模拟生成测试数据和状态,为单元运行准备动态环境。
5、单元测试策略
一般的单元测试策略有3种:孤立的单元测试策略、自顶向下的单元测试策略、自底向上的单元测试策略。
1)孤立的单元测试策略(Isolation Unit Testing)
a.方法:不考虑每个模块与其他模块之间的关系,为每个模块设计桩模块和驱动模块;
每个模块进行独立的单元测试.
b.优点:最简单,最容易操作;
可以达到高的结构覆盖率;
可以并行开开展;
是纯粹的单元测试。
c.缺点:桩函数和驱动函数工作量很大,效率低。
2)自顶向下的单元测试策略(Top Down Unit Testing )
a.方法:先对最顶层的单元进行测试,把顶层所调用的单元做成桩模块;
对第二层进行测试,使用上面已测试的单元做驱动模块;
如此类推直到测试完所有模块。
b.优点:可以节省驱动函数的开发工作量,测试效率较高。
c.缺点:随着被测单元一个一个被加入,测试过程将变得越来越复杂,并且开发和维护的成本将增加。
3)自底向上的单元测试策略(Bottom Up Unit Testing)
a.方法:先对模块调用层次图上最底层的模块进行单元测试,模拟调用该模块的模块做驱动模块;
然后再对上面一层做单元测试,用下面已被测试过的模块做桩模块;
以此类推,直到测试完所有模块。
b.优点:可以节省桩函数的开发工作量,测试效率较高。
c.缺点:不是纯粹的单元测试,底层函数的测试质量对上层函数的测试将产生很大的影响。
6、单元测试过程及主要活动
1)单元测试计划阶段:完成单元测试计划
2)单元测试设计阶段:完成单元测试方案
3)单元测试实现阶段:完成单元测试用例、单元测试教程、单元测试脚本及数据文件
4)单元测试执行阶段:执行单元测试用例。修改发现的问题并进行回归测试,提交单元测试报告
7、单元测试原则
1)对全新的代码或修改过的代码进行测试;
2)单元测试根据单元测试方案和计划进行,排除测试的随意性;
3)必须保证单元测试计划、单元测试方案、单元测试用例等经过评审;
4)当测试用力地测试结果与预期结果不一致时,单元测试的执行人员需如实记录实际的测试结果;
5)只有当测试计划中的结束标准达到时,单元测试才能结束;
6)对被测试单元需达到一定的代码覆盖率要求。
8、单元测试工具
1)代码静态分析工具
2)代码检查工具
3)测试脚本工具
4)覆盖率检测工具
5)内存检测工具
6)专为单元测试设计的工具