1、软件测试技术与测试实训教程 黎连业 王华 李龙 黎照 北京:机械工业出版社 2012.05,第10讲:第10章 单元测试和单元测试实训,单元测试(Unite Testing)又称为模块测试,主要来检验软件设计中最小的单位模块。一般来说模块的内聚程度高,每一个模块只能完成一种功能,因此模块测试的程序规模小,易检查出错误。我们可以通过单元测试进行程序语法检查和程序逻辑检查,验证程序的正确性。单元测试非常重要,因为它影响的范围比较广,主要表现在如果一个单元模块的一个函数或者参数出现问题,会造成后面很多问题的出现,而且如果单元测试做不好,使得集成测试或者后面系统测试工作也做不好。做好单元测试是一个重要
2、而且基础性的工作,主要的测试方法分为人工测试和自动化测试两种方式。 本章重点主要讨论以下内容: 单元测试的概述; 单元测试的步骤; 单元测试需要填写的表格; 单元测试提交的软件BUG清单 单元测试的测试用例; 单元测试的人工测试实训和操作方法; 单元测试的自动化测试实训操作方法。,10.1单元测试的概述 单元测试是一种验证行为。程序中的每一项功能都应测试。作为单元测试,需要考虑以下内容。 10.1.1单元测试的目的 单元测试目的主要有以下几点: (1)检查单元模块内部的错误,为软件的评审验收提供依据。 (2)单元测试是以程序设计说明书和之前所作的测试数据(正常的和错误的)为指导,测试模块内重要
3、的路径,以检查出错误; (3)检验信息能否正确地流入和流出单元; (4)在单元测试工作过程中,其内部数据能否保持其完整性,包括内部数据的形式、内容及相互关系不发生错误,也包括全局变量在单元中的处理和影响。 (5)在为限制数据加工而设置的边界处,能否正确工作。 (6)单元的运行能否做到满足特定的逻辑覆盖。 (7)单元中发生了错误,其中的出错处理措施是否有效。,1012 单元测试的内容 模块是由程序员自己来完成的,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。程序员交付的代码一定是通过编译的代码,但代码通过编译,只是说明了它的语法正确;却无法保证它的语义也一定正确,没有任何人可
4、以轻易承诺这段代码的行为一定是正确的。 执行单元测试,就是为了证明模块代码的行为和系统期望是一致的。这个部分的测试工作是程序开发人员(程序员)进行的。测试人员或者QA(Quality Assurance)人员对单元测试工作是要求对所有的局部的和全局的数据结构、外部接口和程序代码的关键部分进行桌前检查和严格的代码审查。 单元测试是以程序设计说明书为指导,测试模块范围内的重要控制路径,以揭露错误。 当程序编好以后,将它录制在媒体上,或者直接由终端键盘输入到机中进行调试。测试的相对复杂性和所发现的错误受到单元测试所限定的范围的限制。它在执行的过程中紧密的依照程序框架对模块进行测试(调试),测试包含入
5、口和出口的参数,输入和输出信息,错误处理信息,部分边界数值测试。需要在8个方面对所测模块进行检查。,1程序语法检查 程序语法从两个方面进行检查:一是通过编译语言对程序进行检查;二是通过人工检查。编译语言对程序的检查只检查与法的正确性与否,但不能够发现结构性和功能性的错误。人工检查是静态的,检查程序的结构、程序处理的功能以及程序书写的格式。 人工检查程序中错误的有关内容,一般如表10-1所示。,2 模块接口测试 模块接口测试是单元测试的基础,模块接口是模块内与模块外联系的关键部位。当模块通过外部调用时,数据必须能够正确流入,当模块结束问题的处理返回调用模块时,数据必须能够正确流出,这样,模块才能
6、完成它的功能。 模块接口测试应考虑下列因素: 调用其他模块时所给的输入参数与模块的形式参数在个数、属性、顺序上是否匹配; 调用其他模块时所给实际参数的个数是否与被调模块的形式参个数相同; 调用其他模块时所给实际参数的属性是否与被调模块的形式参属性匹配; 调用预定义函数时所用参数的个数、属性和次序是否正确; 输入的实际参数与形式参数的个数是否相同; 输入的实际参数与形式参数的属性是否匹配; 输入的实际参数与形式参数的量纲是否一致; 是否修改了只做输入用的形式参数; 是否存在与当前入口点无关的参数引用; 是否修改了只读型参数; 对全程变量的定义各模块是否一致; 是否把某些约束作为参数传递; 输出给
7、标准函数的参数在个数、属性、顺序上是否正确; 限制是否通过形式参数来传送; 文件属性是否正确; OPEN/CLOSE语句是否正确; 格式说明与输入输出语句是否匹配; 缓冲区大小与记录长度是否匹配; 文件使用前是否已经打开; 是否处理了输入/输出错误; 输出信息中是否有文字性错误; 在结束文件处理时是否关闭了文件。,3 程序逻辑检查 程序逻辑检查主要是检查程序的逻辑结构是否正确?程序中所使用的循环语句的上下项以及循环次数是否有问题?函数或子模块是否有自我调用问题? 4局部数据结构测试局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确的基础。模块的局部数据结构往往是错误的根源,
8、力求发现最常见的几类错误: 不合适或不相容的类型说明; 变量无初值; 变量初始化或省缺值有错; 不正确的变量名(拼错或不正确地截断); 出现上溢、下溢和地址异常。,5路径测试应对模块中重要的执行路径进行测试。由于错误的计算、不正确的比较或不正常的控制流而导致执行路径的错误。路径错误应考虑下列因素: 运算的优先次序不正确或误解了运算的优先次序; 运算的方式错,即运算的对象彼此在类型上不相容; 算法错; 初始化不正确; 浮点数运算精度问题而造成的两值比较不等; 关系表达式中不正确的变量和比较符号表示不正确; 不正确地多循环一次或少循环一次; 错误的或不可能的循环终止条件; 当遇到发散的迭代时不能终
9、止的循环; 不适当地修改了循环变量等。,6 边界条件测试 边界条件测试是单元测试中最重要的一项任务。软件经常在边界上失效,边界条件测试是一项基础测试,也是后面系统测试中的功能测试的重点,边界测试执行的较好,可以大大提高程序健壮性。边界条件测试应考虑下列因素: 程序内有一个n次循环,n次循环应是1n, 而不是0n; 小于、小于等于、等于、大于、大于等于、不等于确定的比较值出错; 出现上溢、下溢和地址异常。,7错误处理测试比较完善的模块设计要求能预见出错的条件,并设置适当的出错处理,以便在一旦程序出错时,能对出错程序重做安排,保证其逻辑上的正确性。这种出错处理也应当是模块功能的一部分。错误处理测试
10、应考虑下列因素: 出错的描述难以理解; 出错的描述不足以对错误定位,不足以确定出错的原因; 显示的错误与实际的错误不符; 对错误条件的处理不正确; 异常处理不当。,8代码书写规范 代码书写规范应考虑下列因素: 模块设计程序框架流程图; 代码书写规范,对齐方式; 代码的注释; 参数类型,数据长度,指针,数组长度大小; 输入输出参数和结果。,1013 单元测试的优点 单元测试有下面的这些优点: 1是一种验证行为 程序中的每一项功能都是测试来验证它的正确性。 2是一种设计技术 单元测试使我们把程序设计成易于调用和可测试的设计,是一种设计技术。 3是一种编写文档的行为 单元测试是一种文档,它是展示函数
11、或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。 4具有回归性 单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。 5保证 保证代码质量,保证代码的可维护性,保证代码的可扩展性。,10.1.4 单元测试所需文档资料 单元测试是以程序设计说明书为指导,测试模块范围内的重要控制路径,以揭露错误。 单元测试所需文档资料有: 系统需求说明书; 系统功能说明书; 系统测试说明书; 程序设计说明书; 测试大纲。,10.2 单元测试的步骤 单元测试是对每个程序的单体调试。主要有以下2步: 程序语法检查; 程序逻辑检查。在程序的逻辑检查之前,首先需要制作
12、测试数据,即:假设一些输入数据和文件数据。测试数据直接影响了程序的调试工作,所以制作的数据应该满足以下几个条件: 数据应能满足设计上要求的上下限及循环次数; 数据应满足程序中的各种检验要求的错误数据; 数据应能适宜于人工对程序的检查工作。,测试数据的内容包含4个方面: 正常的数据 不同的数据 错误的数据 大量的数据 通过以上不同角度的数据检验,证明程序逻辑是对的,程序的调试也就结束了。,在单元(程序)测试期,评价模块的五个主要特性是: 模块接口; 局部数据结构; “重要”的执行路径; 错误处理路径; 影响上述几点的界限条件。,在其它任何测试开始之前,需要测试横穿模块接口的数据流。如果数据不是正
13、确地进入和退出,其它的测试就谈不上。在程序测试中接口测试的清单如下: 输入参数的数目是否等于变元的数目; 参数与变元的属性是否匹配; 参数与变元的单位是否匹配; 传送给被调用模块的变元数是否等于参数的项目; 传送给被调用模块的变元属性是否同参数属性一致; 传送给被调用模块的变元单位是否同参数的单位一致; 属于内部的函数属性数目及变元次序是否正确; 对参数的任何访问是否与当前的入口点无关; 输入是否改动变元; 跨模块的全程量定义是否相容; 限制是否作为变元来传送; 参数是否被重复定义。,程序测试通常附属于编码步骤来考虑。在开发、复审了源代码并检查了语法正确性之后开发设计单元测试的情况。设计信息量
14、复审为建立测试情况提供了指导,使得测试情况有可能发现上面讨论的各类错误。每个测试情况应有一组预期的结果。 由于模块不是一个独立的程序,必须为每个模块测试开发驱动软件和承接软件,在大多数应用中,驱动软件和“主程序”并无区别。客观存在接受测试情况的数据,将这些数据送给模块,并打印有关的结果。承接软件代替被测模块下属模块。承接软件使用下属模块的接口,可以作最少量的数据处理,打印入口检查信息,并将控制返回给它的上级模块。 驱动软件和承接软件代表开销。它们都是要书写的软件,但却不是与最后的软件产品一起支付的。当模块设计成高内聚时,单元测试就简化了。当一个模块只描述一个功能时,测试情况的数量就会减少,就可
15、能会更容易地预计和发现错误。 程序测试实际上是为了发现错误而执行的程序的,但测试不能发现所有的错误,即使是最彻底的切实可行的检测方法,也只能查出程序所存在的错误的一部分,其余的错误在实际使用过程中才能逐渐发现。因为要检查每一种可能的情况,检测的数目是相当大,实际上不可能实现的,另一方面,一个软件的许多问题是无法通过输入来进行检查的,而是需要使用一些特殊的检测方法。 程序测试之后,还需要对每个程序作一份程序测试说明书,以备系统今后修改维护。,程序测试说明书的主要内容是: 说明程序测试数据制作的方法; 测试方法; 测试过程中所产生的问题。 其格式如表10-2所示。,10.3 单元测试需要填写的表格
16、 尽管单元测试是针对模块的测试,但往往会涉及到代码测试和功能测试。编码和测试人员应当对自己所要测试的内容填写一份表,供项目经理、测试经理和总工程师审核以及备查。 具体的单元测试表格如表10-3所示。,10.4单元测试提交的软件BUG清单 单元测试后需要提交软件BUG清单,软件BUG清单的表的格式如表10-4所示。,10.5 单元测试的测试用例 单元测试的测试用例是软件测试的重中之重。我们一般依据测试条件编写测试用例。用例的个数为2n -1个。为了说明怎样设计测试用例,我们用下面的一个例子说明之。 例: 手机类别信息表:用户姓名、用户手机号(卡)、手机类别、手机操作系统。手机类别信息表的数据库结
17、构,如表10-5所示。,现对手机类别数据库中的某人进行查询。假设查询某个人时要有三个查询条件:“姓名” 、“手机类别”、 “手机号码”。 输入查询条件如表10-6所示。,考虑查询条件要么不输入(0),要么输入(1)。 设计的测试用例组合有23个。如表10-7所示。,其中:0表示不输入内容;1表示输入内容。 我们最终得到如下8个测试用例: 1:不输入姓名(0)、不输入身份证号(0)、不输入手机号(0): 2:不输入姓名(0)、不输入身份证号(0)、 输入手机号(1): 3:不输入姓名(0)、 输入身份证号(1)、不输入手机号(0): 4:不输入姓名(0)、 输入身份证号(1)、 输入手机号(1)
18、; 5: 输入姓名(1)、不输入身份证号(0)、不输入手机号(0): 6: 输入姓名(1)、不输入身份证号(0)、 输入手机号(1): 7: 输入姓名(1)、 输入身份证号(1)、不输入手机号(0): 8: 输入姓名(1)、 输入身份证号(1)、 输入手机号(1)。,其中,1:不输入姓名(0)、不输入身份证号(0)、不输入手机号(0),(0,0,0)组表示不输入任何内容,在实际的测试过程中,我们没有必要编写这组测试用例,所以本例子的实际测试用例为23 -1=7个。对于单元测试中所要编写的测试用例,请按照本例子的做法,依此类推,如有N个查询条件,则制作的测试用例个数就有2n -1个。,10.6
19、单元测试的人工测试实训和操作方法,10.110.5节的内容主要是介绍了软件测试中有关单元测试的一些实用技术,下面我们就要进入实际的动手操作环节。 在手机信息管理系统模型进行的单元测试中,我们主要针对“详细查询”模块,它的功能就是输入一个用户名的信息,查询出该用户的所有信息。,下面是“详细查询”模块的截图信息,如图10-1所示。,因为对于详细查询模块的具体说明,在本书的第8章和详细设计说明书中已经做了细致的介绍。所以在这里不再做过多的描述,图10-2是画好的本模块的流程图,在接下来的测试中,我们会根据该流程图为线索,进行详细查询模块的测试。,从上图的内容我们可以分析出,“完全匹配”按钮是测试中的
20、关键点,输入的内容也是测试的关键点。所以在下面的测试用例中,我们会着重考虑到这两个地方。 为了节省时间和语言的简练,详细查询模块的测试用例以及测试后的结果,我们用表一并给出。表10-8所示的内容即是“详细查询”模块的测试用例。,详细查询模块的单元测试我们进行完了。本书中的光盘中有两套“手机信息管理系统模型”的源程序,希望读者可以对这两套程序进行对比测试。,10.7 单元测试的自动化测试实训操作方法 如何使用自动化测试工具进行单元测试?单元测试自动化测试的主要问题如下: 单元自动化测试要清楚的事情和重点; 选择合适的单元自动化测试工具; 单元自动化工具如何使用; 使用自动化工具进行单元测试需要注
21、意哪些问题; 自动化单元测试的重点及工作有哪些及如何解决。,1071 单元自动化测试要清楚的事情和重点 1 单元自动化测试要清楚的事情 单元自动化测试是测试最低层次保证每个函数/方法,或者说最小功能模块的正确性的一种测试。我们要清楚了这样的2件事情: (1) 单元测试是最低层级的测试,它只保证函数(子程序)的可靠性,不保证其它; (2) 单元测试应该能保证每一个函数(子程序)的可靠性。 理论上来说,单元测试和其他测试一样,也是可以纯人工完成的(我们可以写一段某函数的测试代码,然后输入我们的测试输入,观察测试输出,并跟期望值做比较事实上这种人工测试)。但是,单元测试有一点特殊性,就是在一个系统中
22、,函数(子程序模块)会非常非常的多,变化也比软 件的功能频繁的多。面对这么多的函数(子程序模块),这么频繁的变化,进行自动化测试。,2单元自动化测试要清楚的重点n 自动化单元测试的重点应该是: 如何搭建测试环境、测试场景? 如何选择测试用例? 任何测试用例的数据准备都是一个令人头疼的问题,进行白盒测试时一般都需要根据路径、边界值、编码流程来进行测试用例数据的准备。假如,您所选择的测试工具能够自动生成测试用例推荐使用工具自动生成,然后再其自动生成用例的基础上进行编辑强化测试脚本。 如何校验测试结果? 对于测试代码本身,应该尽可能的简单,如果测试本身过于复杂,我们不能保证测试的正确性,测试这个工作
23、就白做了。 单元测试的编写,是由开发人员做的。开发人员最清楚函数(子程序模块)需求,在这种情况下当然就应该是开发人员自己编写测试用例。 在编写测试用例的时候绝不能假定任何函数(子程序模块)的实现,而应该完全按照它应该有的需求来做。 如何准备自动化测试脚本,自动化测试用例通常称为“测试脚本”。 单元测试中单元模块的选择,单元测试基于源码的白盒测试,如何有效的使用测试工具进行单元测试是我们测试工作中需要特别注意的问题,不同于人工测试,自动化测试的执行需要工具消耗计算机系统资源进行测试,如果一次性执行大量测试,不便于测试的记录及测试的执行。所以推荐以类为最小单元模块进行单元测试。,1072 选择适用
24、的单元测试工具进行测试,当然,我们可以选择进行人工测试,任何软件都可以进行人工测试,但是使用人工进行测试有一些问题,如: 回归性问题; 效率问题; 覆盖率问题; 数据可重用性。自动化工具的出现就是为了提高我们的效率和质量问题,好的工具是我们好的助手。如何选择适用自动化工具是我们本节将要讨论的问题。,首先我们来了解一下使用自动化工具进行单元测试的优点。 1)自动化:节省了我们的时间,免去了重复的操作。 2)测试数据重用性:多用于回归测试,也可用于相同功能点的测试数据的准备工作中。 3)测试的可控性:我们完全可以按测试计划来控制单元测试的进度,我们可以选择在合适的时间,使用合适的方法及合适的数据来
25、进行单元测试。,选择单元测试自动化工具我们需要了解我们的测试环境、待测系统类型、开发语言等等。如: 1)基于java语言开发的软件(包括 C/S 及B/S架构的软件),我们可以选择免费开源的Junit 测试工具来进行测试。Junit用于编写和运行可重复的测试。 2)基于C+ 语言开发的软件我们可以选择适用C+ Test 进行测试。C+ Tes 是Parasoft针对C/C+的一款自动化测试工具。C+test支持编码策略增强,静态分析,全面代码走查,单元与组件的 测试,为用户提供一个实用的方法来确保其C/C+代码按预期运行。 3)基于微软C# .net框架开发的软件系统我们可以使用.net un
26、it 测试工具来测试 .netunitye 是基于Nunit系列的单元测试软件之一,如果您有兴趣了解,请自行查阅资料。单元测试工具种类繁多,我们再此就不一一列举。 在选择单元测试工具时,应根据实际情况来进行选择。要考虑一些资金,测试进度等等因素。,107.3 自动化单元测试中需要注意的问题任何测试的执行都需要按照测试计划来操作,测试计划可以有效预防计划的风险,保障计划的顺利实施。执行自动化单元测试的相关人员需要注意如下几点问题: 根据项目开发计划及测试计划来进行测试工作; 开发人员要知道单元测试的目标有哪些; 对于没有测试经验的程序员应主动向有经验的程序员学习; 对于测试工具的掌握要保持在会用
27、水平,并能举一反三学习同类其他测试工具。 要走出开发人员不进行测试的误区。,1074 自动化单元测试工作重点使用自动化进行单元测试工作中的重点: 单元测试中单元模块的选择 单元测试基于源码的白盒测试,如何有效的使用测试工具进行单元测试是我们测试工作中需要特别注意的问题,不同于人工测试,自动化测试的执行需要工具消耗计算机系统资源进行测试,如果一次性执行大量测试,不便于测试的记录及测试的执行。所以推荐以类为最小单元模块进行单元测试。 测试用例数据的准备 任何测试用例的数据准备都是一个令人头疼的问题,进行白盒测试时一般都需要根据路径、边界值、编码流程来进行测试用例数据的准备。假如,您所选择的测试工具
28、能够自动生成测试用例推荐使用工具自动生成,然后再其自动生成用例的基础上进行编辑强化测试脚本。,1075 自动化单元测试案例 在选择适用的测试工具一节中我们介绍到了选择适用工具的一些情况,了解了一些单元测试工具的现状。从本节开始我们以将以手机信息管理系统为例来讲解如何使用自动化测试工具进行单元测试。 首先介绍本次测试的环境,测试环境如表10-9示。,我们所使用的测试模型基于VC+ 6.0 IDE 开发环境使用C+ 语言进行开发,所用到的数据库为Microsoft Sql Server 2005 。所以我们在自动化测试工具的选择方面选择使用C+ Test ,以C+ Test 为原型进行讲述如何使用
29、自动化测试工具。 C+ Test是Parasoft公司出品的一个针对C/C+源代码进行代码风格测试,自动化单元测试的工具。可以去http:/网站上下载试用。 C+ Test可以帮助我们检查程序的编码是否规范,判断是否严格按编码规范进行开发。可以对C/C+源代码进行分析,自动生成相应的测试用例,对函数进行初步的测试。C+ Test的使用比较简单。可以自己新建一个工程,也可以根据一个VC工程生成一个工程。可以对整个工程进行全面的测试,也可以一次只对一个C/C+源文件进行测试。 C+Test是一个功能强大的自动化C/C+单元级测试工具,可以自动测试任何C/C+函数、类,自动生成测试用例、测试驱动函数
30、或桩函数,在自动化的环境下极其容易快速的将单元级的测试覆盖率达到100%。,我们主要使用C+ Test 来进行单元测试。 本次测试我们只针对添加管理员模块中其中一部分代码进行测试,其他模块测试执行您参照我们这次测试来自行试验。 如同大多数windows 桌面应用程序一样 C+ Test 主要也是由菜单栏、工具栏、主窗口及状态栏来组成。如图10- 3所示:,加载工程:我们使用File 菜单下 New project 来新建一个工程,当然您也可以选择载入原来已存在的C+ Test 工程。点击完成后会出现选择工程类型窗口,如图10-4所示 ,我们可以在此选择创建空工程、基于VC+ 6.0 、C+.N
31、et 及C+.Net2003工程,根据我们的手机信息管理系统我们选择适用 VC+ 6.0 工程 然后加载我们的工程 。,点击ok 即可把文件加载进来,文件加载进来以后我们开始依据测试计划来进行测试。 表10-10测试需要检查详细说明。,在进行测试的时候需要注意,推荐以单个文件为基准,以文件中的类为单元模块进行测试。 原因是C+ Test 进行测试时测试工作量非常大,如果某个工程非常庞大在测试进行中可能会出现某些问题,如系统资源不够用,出先死锁,测试进行中需要进行异常处理操作等。 因此建议逐个文件进行测试,实时观察记录测试中出现的异常。 在工程目录窗口中选择要进行测试的文件,点击工具栏中按钮就可
32、以开始测试,当然C+Test为我们提供的不仅仅时进行单元测试,因此我们可以在右面小箭头中选择我们需要进行的测试如图10-5所示。此处我们按照C+Test 默认的测试项来展开测试。,开始测试后,C+ Test 会为我们自动进行单元测试,覆盖率测试及代码规范检查,需要特别提到一点的是,C+ Test 会为我们自动创建测试用例,省去了开发人员最为头疼的问题。如图10-6所示 。,在执行完测试后我们可以在主窗口中编辑我们的测试用例及查看测试用例执行情况。也可以自行添加删除测试用例。 假如,您对测试用例所覆盖的测试点不太满意的话您可以自行添加或修改测试用例,在测试用例配置选项中即可更改配置。如图10-7
33、所示 。,下面我们看一个C+ Test 在单元测试中为我们生成的测试用例,如在添加管理员模块中Recordset15 类中的HRESULT AddNew(const _variant_t &, const _variant_t &) 函数进行测试时C+ Test 为我们自动生成了如下几个测试用例 如表10-11 所示的测试用例及执行结果。,从结果中我们可以看到C+Test 为本单元模块准备了9个测试点,共准备了277个测试用例执行了227个测试用例,其中通过的测试209个,失败的测试用例4个,错误的测试用例14个。从此处我们就可以看出使用工具进行测试的优越性,假如人工测试,准备这些测试数据就是一个庞大的工作量。 相信有了如此方便的测试工具相助,开发人员应该不会对单元测试再头疼了吧,所以在资金允许的情况下,希望能够使用自动化工具来进行测试,改变单元测试的现状。本书随书光盘中提供手机信息管理系统源码,如果您想进行验证测试可以自行进行试验。,第 10 讲 完 谢 谢!,