工作性质不同决定了工作侧重点也不同,因此程序开发人员在单元测试过程中关注更多的是程序代码本身和已经实现的功能。因此,站在他们的角度看,单元测试的过程就是在编写测试方法之前:
首先考虑如何对方法进行测试;
然后编写测试代码;
下一步就是运行某个测试,或者同时运行该单元的所有测试,确保所有测试都通过。
下图从宏观的角度概括了单元测试的工作过程图。
1.单元测试进入和退出准则
进入原则如下图所示:
要素 | 判断准则 |
详细设计说明书
单元测试用例 | 经过审查
获得批准 进入配置库 |
退出原则如下图所示:
要素 | 判断准则 |
源代码文件
源代码文件清单 | 源代码文件获得批准
源代码文件进入配置库的源代码区 测试用例源代码通过同级评审 |
软件Bug 清单
单元测试报告 | 提交测试负责人
提交软件产品配置管理 |
注:与代码相关的数据文件、修改日志、编译环境文件和源程序文件清单也包含在源代码文件中。
2.单元测试过程
(1)准备阶段:
- 根据程序员实际水平进行有关编程语言、编程规范、编程方法、编程工具、调试方法、配置管理等方面的培训;
- 根据测试人员的实际水平进行有关测试方法、测试工具、问题汇报方法等方面的培训;有关被测产品的功能培训。
- 准备开发及测试工具和环境,如有必要在各编码组内对临时的编译环境和调试方法进行约定。
- 对详细设计说明书需要做进一步确认工作,保证接口、工作流程的一致性。如果是多人参与开发,还需根据实际情况对参与人员进行设计讲解工作。
- 根据单元划分情况编写单元测试用例,并审查是否达到测试需求。
(2)编制阶段
- 程序员依据详细设计,进行程序单元的编制工作(包括建立相关的构造环境),并调试和检查;
- 在更正测试问题时,修改源码和测试用例,提交新源码文件。
(3)代码审查阶段
- 将编制的源代码文件进行静态代码审查,填写代码审查表;
在代码审查阶段,必须执行的活动有以下几个项目:
1.检查算法的逻辑正确性:确定编写的代码算法、数据结构定义(队列、堆栈)是否实现了模块或方法所要求的功能。
2.模块接口的正确性检查:确定形式参数个数、数据类型、顺序是否正确;确定返回值类型及返回值的正确性。
3.输入参数有没有做正确性检查:如果没有做正确性检查,确定该参数是否的确无需做参数正确性检查,否则请添加参数的正确性检查。经验表明,缺少参数正确性检查的代码是造成软件系统不稳定的主要原因之一。
4.调用其它方法接口的正确性:检查实参类型正确与否、传入参数值正确与否、参数个数正确与否,特别是具有多态性的方法。返回值正确与否,有没有误解返回值所表示的意思。
5.出错处理:模块代码要求能预见出错的条件,并设置适当的出错处理,以便程序出错时,能重做安排,保证其逻辑的正确性,这种出错处理应当是模块功能的一部分。
6.保证表达式、SQL语句的正确性;检查所编写的SQL语句的语法、逻辑的正确性。
7.检查常量或全局变量使用的正确性;确定所使用的常量或全局变量的取值和数值、数据类型;保证常量每次引用同它的取值、数值和类型的一致性。
8.表示符定义的规范一致性;保证变量命名能够见名知义,并且简洁、规范、容易记忆、最好能够拼读。
9.程序风格的一致性、规范性;代码必须保证符合企业规范,保证所有成员的代码风格一致、规范、工整。
10.检查程序中使用到神秘数字是否采用了表示符定义。
11.检查代码是否可以优化、算法效率是否最高。
12.检查程序是否清晰、简洁、容易理解。注意:冗长的程 序也可能是清晰的。
13.检查方法内部注释是否完整;是否清晰简洁;是否正确反映代码的功能,错误的注释比没有注释更糟;是否做了多余注释;对于简单一看就懂的代码没有必要注释。
14.检查注释文档是否完整;对包、类、属性、方法功能、参数、返回值的注释是否正确且容易理解;是否会落下或多了某个参数的注释,参数类型是否正确,参数限定值是否正确。
(4)单元测试阶段
从配置库获取源码文件,设计测试用例,执行测试用例并利用相关测试工具对单元代码进行测试,将测试结论填写到单元测试报告和软件Bug清单中。
把软件Bug清单和测试用例执行结果提交测试负责人,并纳入质量管理。对源码文件进行的测试,视程序存在缺陷的情况,可能要重复进行直至问题解决。
(5)评审、提交阶段
对源代码文件进行同级评审,给出评审结论(由审查人员填写产品批准表),并将其提交配置库中。
上述过程完成后,开发人员应提交源代码、代码清单、单元测试用例代码及单元测试报告。测试人员提交该版本的软件Bug清单,代码审查人员提交产品批准表。
上面所列出的测试环节可供读者参考,在具体的单元测试过程中可能会因实际工作要求的不同和具体单元测试目标的不同会有所增加、补充或修改,当然也有一些公司内部会专门规定相关的单元测试流程和单元测试规范。
单元测试策略
自顶向下的单元测试策略
步骤:
1.从最顶层开始,为顶层模块编写桩模块。
2.对第二层测试,使用上面已测试的单元做驱动模块。
3.依次类推,直到全部单元测试结束。
优点:不需编写驱动模块,可以在集成测试前为系统提供早期的集成途径。由于详细设计一般都是自顶向下进行设计的,这样自顶向下的单元测试测试策略在顺序上同详细设计一致,因此测试可以与详细设计和编码工作重叠进行。
缺点:单元测试被桩模块控制,随着单元测试不断进行,测试过程会变得越来越复杂,测试难度以及开发和维护成本都不断增加;低层次结构覆盖率难以得到保证;由于需求变更或其他原因而必须更改任何一个单元时,就必须重新测试该单元下层调用的所有单元;低层单元测试依赖顶层测试无法进行并行测试,使测试进度受到影响,延长测试周期。
总结:该测试策略成本要高于孤立的单元测试成本,从测试成本方面考虑并不是最佳的单元测试策略。在实际工作中,当单元已经通过独立测试后,我们可以选择此方法。
自底向上的单元测试策略
步骤:
1.先对模块调用图上的最底层模块开始测试,模拟调用该模块的模块为驱动模块。
2.对上一层模块进行单元测试,用被测试过的模块做桩模块。3.依此类推,直到全部单元测试结束。
优点:不需要单独设计桩模块。无需依赖结构设计,可以直接从功能设计中获取测试用例;可以为系统提供早期的集成途径;在详细设计文档中缺少结构细节时可以使用该测试策略。
缺点:随着单元测试不断进行,测试过程越来越复杂,测试周期延长,测试和维护成本增加;随着基本单元逐步加入,系统会变得异常庞大,因此测试人员不容易控制;越接近顶层模块结构覆盖率就越难以保证;顶层测试易受底层模块变更影响,任何模块修改后直接或间接调用该模块的所有单元都要重新测试;在底层单元测试完毕后才能进行顶层单元测试,并行性不好;自底向上的单元测试不能和详细设计、编码同步进行。
总结:该测试策略比较合理,尤其是需要考虑对象或复用时。它属于面向功能而非面向结构的测试。不适用高覆盖率为目标或者软件开发时间紧张的项目。
孤立测试
步骤:无需考虑每个模块与其它他模块之间的关系,分别为每个模块单独设计桩模块和驱动模块,逐一完成所有单元模块的测试。
优点:该方法简单、容易操作,因此所需测试时间短,能够达到高覆盖率。因为一次测试只需要测试一个单元,其驱动模块比自底向上的驱动模块设计简单,而其桩模块的设计也比自顶向下策略中使用的桩模块简单。另外,各模块之间不存在依赖性,所以单元测试可以并行进行。如果在测试中增添人员,可以缩短项目开发时间。
缺点:不能为集成测试提供早期的集成途径,依赖结构设计信息,需要设计多个桩模块和驱动模块,增加额外的测试成本。
总结:该方法是比较理想的单元测试方法。如辅助适当的集成测试策略,有利于缩短项目的开发时间。
综合测试
在单元测试中,为了有效地减少开发桩模块和驱动模块的工作量,可以考虑以上三种方法结合使用。
下面是判断三角形类型的C语言代码:
#include <stdio.h> int x,y,z Void GetInput(int a,int b,int c) { int c1=0,c2=0,c3=0; do {printf("\n enter 3 integers(1<=x<=200) which are sids of triangle\n"); C1=(1<=a)&&(a<=200); C2=(1<=b)&&(b<=200); C3=(1<=c)&&(c<=200); If(!c1)printf("value of a is not in the range of permitted values\n"); If(!c2)printf("value of b is not in the range of permitted values\n"); If(!c3)printf("value of c is not in the range of permitted values\n");} while(!c1||!c2||!c3); x=a;y=b;z=c; printf("\n side A id %d",x); printf("\n side B id %d",Y); printf("\n side C id %d",z); } int IsTrian(int a,int b,int c) { if((a<(b+c))&&(b<(a+c))&&(c<(a+b))) return 1; else return 0;} Void DeterType(int a,int b,int c) { if(!IsTrian(a,b,c))printf("\n not a triangle!\n"); else{if((a==b)&&(b==c))printf("\n equilareral\n"); else{if(a!=b)&&(a!=c)&&(b!=c)) printf("\n scalene\n"); else printf("\n isosceles \n");} } } int main() { GetInput(x,y,z); DeterType(x,y,z); return 0; }
对于如图所示的模块结构在进行单元测试时可以采取自底向上和孤立的单元测试法结合,即所谓的综合测试。首先用自底向上的单元测试法开发模块GetInput()和IsTrian()的驱动模块并测试这两个模块,然后用孤立测试法开发DeterType()的桩和驱动器并测试, 再开发main()的桩模块并测试,则完成整个模块的单元测试。
相关文章:
125jz网原创文章。发布者:江山如画,转载请注明出处:http://www.125jz.com/1701.html