1、第五章 单元测试5.15.1单元测试基本概念单元测试基本概念5.25.2单元测试的目标和任务单元测试的目标和任务5.35.3静态测试静态测试5.45.4驱动程序和桩程序驱动程序和桩程序5.55.5调试与评估调试与评估5.65.6单元测试的管理单元测试的管理5.75.7单元测试工具单元测试工具2传统定义v20世纪世纪70年代年代Smalltalk引入单元测试,单引入单元测试,单元通常指的是一个方法或函数元通常指的是一个方法或函数v作用作用 提高代码质量提高代码质量 深入理解类或方法的功能需求深入理解类或方法的功能需求v定义定义 单元测试是一段代码调用另外一段代码,检单元测试是一段代码调用另外一段
2、代码,检验一些假设的正确性验一些假设的正确性 如果假设的结果错误,测试失败如果假设的结果错误,测试失败优秀单元测试的特性v自动的、可重复的自动的、可重复的v容易实现容易实现v一旦写好,将来都可使用一旦写好,将来都可使用v任何人都可运行任何人都可运行v单击一个按钮就可运行单击一个按钮就可运行v可以快速地运行可以快速地运行什么是单元测试v两周或两个月、甚至两年前写的单元测试,还可两周或两个月、甚至两年前写的单元测试,还可以运行并得到结果吗?以运行并得到结果吗?v两个月前写的单元测试,任何一位团队成员都可两个月前写的单元测试,任何一位团队成员都可以运行并得到结果吗?以运行并得到结果吗?v是否可以在几
3、分钟内跑完所有的单元测试是否可以在几分钟内跑完所有的单元测试v是否可以单击一个按钮就执行全部单元测试是否可以单击一个按钮就执行全部单元测试v是否能在几分钟内写一个基本的单元测试是否能在几分钟内写一个基本的单元测试集成测试v汽车引擎由许多零部件组成,各部件相互依赖、汽车引擎由许多零部件组成,各部件相互依赖、共同作用,所有部件集成在一起才能使汽车动起共同作用,所有部件集成在一起才能使汽车动起来。因此,发动汽车是引擎的集成测试,如果失来。因此,发动汽车是引擎的集成测试,如果失败,所有部件都失败,如果成功,则全部部件都败,所有部件都失败,如果成功,则全部部件都成功。成功。v软件也是同样道理。通过用户界
4、面来测试程序功软件也是同样道理。通过用户界面来测试程序功能,单击一些按钮,触发一系列事件,各种各样能,单击一些按钮,触发一系列事件,各种各样的类和组件一起工作。的类和组件一起工作。集成测试与单元测试区别v集成测试意味着把两个或更多相互依赖的软件模集成测试意味着把两个或更多相互依赖的软件模块作为一组进行测试。块作为一组进行测试。v当集成测试失败,所有参与的软件单元都可能存当集成测试失败,所有参与的软件单元都可能存在故障,这使我们难以定位缺陷在故障,这使我们难以定位缺陷v集成测试运行多个集成到一起的代码单元,用来集成测试运行多个集成到一起的代码单元,用来确认软件中应该出现的一个或多个预期结果确认软
5、件中应该出现的一个或多个预期结果v单元测试只孤立地运行和测试某一个单元单元测试只孤立地运行和测试某一个单元与单元测试相比,集成测试的不足v场景场景1:在应用程序生命周期中,经常需要改动:在应用程序生命周期中,经常需要改动代码,极有可能会无意中破坏现有功能,称为代码,极有可能会无意中破坏现有功能,称为“意外缺陷意外缺陷”,当进行到项目末期,程序员顶着交,当进行到项目末期,程序员顶着交付压力修复缺陷时,这种情况更是层出不穷付压力修复缺陷时,这种情况更是层出不穷v如果这种影响能在不到三分钟即可知道,岂不如果这种影响能在不到三分钟即可知道,岂不是很棒?是很棒?v优秀的测试应以其本来的、非手工的形式轻松
6、优秀的测试应以其本来的、非手工的形式轻松执行执行v场景场景2:两个月前写的单元测试,任何一位团队:两个月前写的单元测试,任何一位团队成员都可以运行并得到结果吗?成员都可以运行并得到结果吗?v必须确保你的改动不会影响到别人的代码必须确保你的改动不会影响到别人的代码v因为担心其他代码依赖于正在改动的代码,所以因为担心其他代码依赖于正在改动的代码,所以很多程序员都怕改动老系统中的遗留代码。面临很多程序员都怕改动老系统中的遗留代码。面临的风险是系统稳定性不可预知的风险是系统稳定性不可预知v优秀的测试应该是任何人都可使用、运行优秀的测试应该是任何人都可使用、运行v场景场景3:是否可以在几分钟内跑完所有的
7、单元测:是否可以在几分钟内跑完所有的单元测试?试?v如果不能很快运行完成测试,你就不会经常运如果不能很快运行完成测试,你就不会经常运行测试(可能一天,或一周,甚至一个月才运行测试(可能一天,或一周,甚至一个月才运行一次)。行一次)。v当改动代码后,你肯定希望尽早得到反馈,看当改动代码后,你肯定希望尽早得到反馈,看看是否影响了既有功能,如果不经常运行测试看是否影响了既有功能,如果不经常运行测试,间隔越久,代码改动就越多,出现问题后,间隔越久,代码改动就越多,出现问题后,就要花更多时间来排错就要花更多时间来排错v场景场景4:可以单击一个按钮就运行所有单元测试:可以单击一个按钮就运行所有单元测试吗?
8、吗?v如果做不到这一点,就意味着必须事先配置好运如果做不到这一点,就意味着必须事先配置好运行测试的机器,而后才能正常运行,又或者单元行测试的机器,而后才能正常运行,又或者单元测试还未完全自动化。如果单元测试未完全自动测试还未完全自动化。如果单元测试未完全自动化,那么你就不会反复运行,团队中其他人也不化,那么你就不会反复运行,团队中其他人也不会会v优秀的测试应该运行起来不费事、不费力优秀的测试应该运行起来不费事、不费力v场景场景5:能否在几分钟内写一个基本的单元测试:能否在几分钟内写一个基本的单元测试?v辨别集成测试最简单的一个方法,不仅看它是辨别集成测试最简单的一个方法,不仅看它是否要花时间运
9、行,更要看它是否要花时间做适否要花时间运行,更要看它是否要花时间做适当的准备和实现。写集成测试很花时间。当的准备和实现。写集成测试很花时间。v单元测试更倾向于测试可能出错的每个小细节单元测试更倾向于测试可能出错的每个小细节。v优秀的测试应该写起来很顺利,不耗时优秀的测试应该写起来很顺利,不耗时优秀单元测试定义v单元测试(单元测试(Unit Test)是一段自动化的代码,)是一段自动化的代码,用来调用被测试的方法或类,而后验证基于该方用来调用被测试的方法或类,而后验证基于该方法或类的逻辑行为的一些假设。单元测试几乎总法或类的逻辑行为的一些假设。单元测试几乎总是用单元测试框架来写的。它写起来很顺手
10、,运是用单元测试框架来写的。它写起来很顺手,运行起来不费时。它是全自动的、可信赖的、可读行起来不费时。它是全自动的、可信赖的、可读性强的、可维护的性强的、可维护的v不包含任何逻辑的代码,通常不需要测试不包含任何逻辑的代码,通常不需要测试传统方式测试驱动开发TDD一般步骤v写一个失败测试,证明最终产品还缺少代码或写一个失败测试,证明最终产品还缺少代码或功能功能 编写测试时要当做生产代码已经可用编写测试时要当做生产代码已经可用v编写生产代码,满足测试期望,使测试通过编写生产代码,满足测试期望,使测试通过 代码尽可能写得简单代码尽可能写得简单v重构代码重构代码 测试通过后,继续写下一个单元测试,或重
11、测试通过后,继续写下一个单元测试,或重构代码,使其可读性更强,消除代码冗余等构代码,使其可读性更强,消除代码冗余等v重构是指改变一段代码而不改变其功能。重构是指改变一段代码而不改变其功能。v你可能做过的重构你可能做过的重构 如果修改过方法名称如果修改过方法名称 将一个大方法拆分成几个小的方法将一个大方法拆分成几个小的方法v重构是一个非常有价值的实践,因为它确保代码重构是一个非常有价值的实践,因为它确保代码更容易阅读,更容易维护、调试和变更更容易阅读,更容易维护、调试和变更v同时,之前写的所有测试仍然可以通过。同时,之前写的所有测试仍然可以通过。v优秀单元测试优秀单元测试 一段自动化代码,调用一
12、个方法,然后检查基一段自动化代码,调用一个方法,然后检查基于该方法或类逻辑行为的一些假设于该方法或类逻辑行为的一些假设 使用单元测试框架使用单元测试框架 写起来很容易写起来很容易 运行起来很快运行起来很快 开发团队中任何人都能重复运行开发团队中任何人都能重复运行5.15.1单元测试概念单元测试概念n 单元测试又称模块测试,是针对软件设计的最小单元测试又称模块测试,是针对软件设计的最小单位单位 程序模块,进行正确性检验的测试工作程序模块,进行正确性检验的测试工作。n 单元测试主要需要测试者非常清楚代码内部结构单元测试主要需要测试者非常清楚代码内部结构,单元测试是软件开发人员的职责,单元测试是软件
13、开发人员的职责,测试人员一测试人员一般不参与单元测试般不参与单元测试。19n 一般单元的选择依据几个条件:一般单元的选择依据几个条件:单元必须是可测试的。单元必须是可测试的。单元的行为或输出是可观测的。单元的行为或输出是可观测的。有一个明确的可定义的边界或接口。有一个明确的可定义的边界或接口。20n 单元:单元能够实现需求规格的最小组件,可以单元:单元能够实现需求规格的最小组件,可以是:是:函数(函数(FunctionsFunctions)过程(过程(ProceduresProcedures)类(类(ClassesClasses)页面(页面(webweb)4GL4GL(第四代语言)的菜单和显示
14、(第四代语言)的菜单和显示 21为什么要进行单元测试n 问题一:单元测试浪费了太多的时间问题一:单元测试浪费了太多的时间 n 问题二:单元测试仅仅是证明这些代码做了什么问题二:单元测试仅仅是证明这些代码做了什么 n 问题三:我是个很棒的程序员,我是不是可以不问题三:我是个很棒的程序员,我是不是可以不进行单元测试?进行单元测试?n 问题四:不管怎样,集成测试将会抓住所有的问题四:不管怎样,集成测试将会抓住所有的Bug Bug n 问题五:它的成本效率不高问题五:它的成本效率不高 225.2单元测试目标和任务n 单元测试的主要目的有:单元测试的主要目的有:验证代码和详细设计相符合;验证代码和详细设
15、计相符合;发现设计中存在的错误;发现设计中存在的错误;发现在编码过程中引入的错误;发现在编码过程中引入的错误;23 单元测试目标单元测试目标模块模块接口出错处理独立路径边界条件局部数据结构确保各单元模块被正确的编码24v数据或信息是否能正确地流入和流出单元数据或信息是否能正确地流入和流出单元v在单元工作过程中在单元工作过程中,其内部数据能否保持其完整性其内部数据能否保持其完整性v在数据处理的边界处能否正确工作在数据处理的边界处能否正确工作v单元的运行能否做到满足特定的逻辑覆盖单元的运行能否做到满足特定的逻辑覆盖v单元中发生了错误单元中发生了错误,其中的出错处理是否有效其中的出错处理是否有效v指
16、针是否被错误引用指针是否被错误引用,内存是否及时释放内存是否及时释放v有没有安全隐患有没有安全隐患,是否使用了不恰当的字符串处理是否使用了不恰当的字符串处理函数函数25单元测试的任务v1单元中所有独立执行路径测试单元中所有独立执行路径测试v2单元局部数据结构测试单元局部数据结构测试v3单元接口测试单元接口测试v4单元边界条件测试单元边界条件测试v5单元的各条错误处理通路测试单元的各条错误处理通路测试v6内存分析内存分析26单元中所有独立执行路径v常用方法常用方法:基本路径测试和循环测试基本路径测试和循环测试v常见错误常见错误:(1)误解或用错了算符优先级误解或用错了算符优先级 (2)混合类型运
17、算混合类型运算 (3)变量初值错变量初值错 (4)精度不够精度不够 (5)表达式符号错表达式符号错27v常用方法常用方法:比较判断与控制流比较判断与控制流 常见问题常见问题:(1)不同数据类型对象之间进行比较不同数据类型对象之间进行比较 (2)错误地使用逻辑运算符或优先级错误地使用逻辑运算符或优先级 (3)因计算机表示的局限性因计算机表示的局限性,期望理论上相等期望理论上相等 而实际上不相等的两个量相等而实际上不相等的两个量相等 (4)比较运算或变量出错比较运算或变量出错 (5)循环终止条件或不可能出现循环终止条件或不可能出现 (6)迭代发散时不能退出迭代发散时不能退出 (7)错误地修改了循环
18、变量错误地修改了循环变量28单元局部数据结构测试v常见错误常见错误 (1)不合适或不相容的类型说明不合适或不相容的类型说明 (2)变量无初值变量无初值 (3)变量初始化或默认值有错变量初始化或默认值有错 (4)不正确的变量名不正确的变量名 (5)出现上溢出现上溢,下溢和地址异常下溢和地址异常29单元接口测试v主要测试内容主要测试内容 (1)输入的实际参数与形式参数个数输入的实际参数与形式参数个数,类型等是否类型等是否匹配匹配,一致一致 (2)调用其他单元时所给实际参数与被调单元的调用其他单元时所给实际参数与被调单元的形式参数个数形式参数个数,属性和量纲是否匹配属性和量纲是否匹配 (3)调用预定
19、义函数时所用参数的个数调用预定义函数时所用参数的个数,属性和次属性和次序是否正确序是否正确 (4)是否存在与当前入口点无关的参数引用是否存在与当前入口点无关的参数引用 (5)是否修改了只读型参数是否修改了只读型参数 (6)对全程变量的定义各单元是否一致对全程变量的定义各单元是否一致 (7)是否把某些约束作为参数传递是否把某些约束作为参数传递30单元边界条件测试v常用方法常用方法:边界值分析边界值分析 单元测试中忽略边界条件的测试单元测试中忽略边界条件的测试,在以后的测在以后的测试中很难被发现试中很难被发现,即使发现后对其跟踪即使发现后对其跟踪,取其根源取其根源也是不容易的也是不容易的31单元的
20、各条错误处理通路测试v主要测试问题主要测试问题 (1)输出的出错信息难以理解输出的出错信息难以理解 (2)记录的错误与实际遇到的错误不相符记录的错误与实际遇到的错误不相符 (3)在程序自定义的出错处理段运行之前在程序自定义的出错处理段运行之前,系统已系统已介入介入 (4)异常处理不当异常处理不当 (5)错误陈述中未能提供足够的定位出错信息错误陈述中未能提供足够的定位出错信息32 单元测试方法单元测试方法n 通常合格的代码应该具备以下性质:正确性、清通常合格的代码应该具备以下性质:正确性、清晰性、规范性、一致性、高效性等(根据优先级晰性、规范性、一致性、高效性等(根据优先级别排序)。别排序)。正
21、确性是指代码逻辑必须正确,能够实现预期的功能正确性是指代码逻辑必须正确,能够实现预期的功能。清晰性是指代码必须简明、易懂,注释准确没有歧义清晰性是指代码必须简明、易懂,注释准确没有歧义。规范性是指代码必须符合企业或部门所定义的共同规规范性是指代码必须符合企业或部门所定义的共同规范包括命名规则,代码风格等等。范包括命名规则,代码风格等等。一致性是指代码必须在命名上(如:相同功能的变量一致性是指代码必须在命名上(如:相同功能的变量尽量采用相同的标示符)、风格上都保持统一。尽量采用相同的标示符)、风格上都保持统一。高效性是指代码不但要满足以上性质,而且需要尽可高效性是指代码不但要满足以上性质,而且需
22、要尽可能降低代码的执行时间。能降低代码的执行时间。33 单元测试方法单元测试方法n 在代码编写完成后的单元测试工作主要分为两个在代码编写完成后的单元测试工作主要分为两个步骤即人工静态检查(即静态测试)和动态执行步骤即人工静态检查(即静态测试)和动态执行测试(即动态测试)测试(即动态测试)n 动态测试主要是黑盒测试和白盒测试动态测试主要是黑盒测试和白盒测试n 单元测试的依据是详细设计和概要设计单元测试的依据是详细设计和概要设计 345.4 驱动程序和桩程序v驱动模块(驱动模块(driverdriver):用以模拟被测模块的上级程用以模拟被测模块的上级程序序,能够调用被测模块能够调用被测模块,相当
23、于所测模块的主程序相当于所测模块的主程序。v桩模块(桩模块(stubstub):用以模拟被测模块工作过程调用用以模拟被测模块工作过程调用的下层模块的下层模块.35被测单元驱动模块桩模块1桩模块桩模块N测试结果测试用例 单元测试环境36 单元测试策略单元测试策略 单元测试涉及到的测试技术通常有:针对被测单单元测试涉及到的测试技术通常有:针对被测单元需求的功能测试、用于代码评审和代码走读的静元需求的功能测试、用于代码评审和代码走读的静态测试、白盒测试、状态转换测试和非功能测试。态测试、白盒测试、状态转换测试和非功能测试。为了提高单元测试的质量,只了解这些单元测试为了提高单元测试的质量,只了解这些单
24、元测试技术还远远不够,还要选择合适的测试策略。在选技术还远远不够,还要选择合适的测试策略。在选择测试策略时,主要考虑如下择测试策略时,主要考虑如下3 3种方式:自顶向下种方式:自顶向下(Top Down Unit TestingTop Down Unit Testing)的单元测试策略、自)的单元测试策略、自底向上的单元测试策略(底向上的单元测试策略(Bottom up Unit Bottom up Unit TestingTesting)和孤立的单元测试策略。)和孤立的单元测试策略。37 自顶向下的单元测试策略自顶向下的单元测试策略 一)步骤:一)步骤:1.1.从最顶层开始,把顶层调用的单元
25、做成桩模块从最顶层开始,把顶层调用的单元做成桩模块。2.2.对第二层测试,使用上面已测试的单元做驱动对第二层测试,使用上面已测试的单元做驱动模块。模块。3.3.依次类推,直到全部单元测试结束。依次类推,直到全部单元测试结束。二)优点:可以在集成测试之前为系统提供早期的二)优点:可以在集成测试之前为系统提供早期的集成途径。集成途径。三)缺点:单元测试被桩模块控制,随着单元测试三)缺点:单元测试被桩模块控制,随着单元测试的不断进行,测试过程也会变得越来越复杂,测试的不断进行,测试过程也会变得越来越复杂,测试难度以及开发和维护的成本都不断增加;难度以及开发和维护的成本都不断增加;38 要求的低层次的
26、结构覆盖率也难以得到保证;要求的低层次的结构覆盖率也难以得到保证;由于需求变更或其他原因而必须更改任何一个单由于需求变更或其他原因而必须更改任何一个单元时,就必须重新测试该单元下层调用的所有单元时,就必须重新测试该单元下层调用的所有单元;低层单元测试依赖顶层测试,无法进行并行元;低层单元测试依赖顶层测试,无法进行并行测试,使测试进度受到不同程度的影响,延长测测试,使测试进度受到不同程度的影响,延长测试周期。试周期。四)总结:从上述分析中,不难看出该测试策略四)总结:从上述分析中,不难看出该测试策略的成本要高于孤立的单元测试成本,因此从测试的成本要高于孤立的单元测试成本,因此从测试成本方面来考虑
27、,并不是最佳的单元测试策略。成本方面来考虑,并不是最佳的单元测试策略。39 自底向上的单元测试自底向上的单元测试 一)步骤:一)步骤:1 1、先对模块调用图上的最底层模块开始测试,、先对模块调用图上的最底层模块开始测试,模拟调用该模块的模块为驱动模块模拟调用该模块的模块为驱动模块 2 2、其次,对上一层模块进行单元测试,用已经、其次,对上一层模块进行单元测试,用已经被测试过的模块做桩模块被测试过的模块做桩模块。3 3、依次类推,直到全部单元测试结束。、依次类推,直到全部单元测试结束。二)优点:不需要单独设计桩模块。二)优点:不需要单独设计桩模块。三)缺点:随着单元测试的不断进行,测试过程三)缺
28、点:随着单元测试的不断进行,测试过程会变得越来越复杂,测试周期延长,测试和维护的会变得越来越复杂,测试周期延长,测试和维护的成本增加;随着各个基本单元逐步加入,系统会变成本增加;随着各个基本单元逐步加入,系统会变得异常庞大,因此测试人员不容易控制;越接近顶得异常庞大,因此测试人员不容易控制;越接近顶层的模块的测试其结构覆盖率就越难以保证;层的模块的测试其结构覆盖率就越难以保证;40 另外,顶层测试易受底层模块变更的影响,任另外,顶层测试易受底层模块变更的影响,任何一个模块修改之后,直接或间接调用该模块的何一个模块修改之后,直接或间接调用该模块的所有单元都要重新测试。所有单元都要重新测试。由于只
29、有在底层单元测试完毕之后才能够进行由于只有在底层单元测试完毕之后才能够进行顶层单元的测试,所以并行性不好。另外,自底顶层单元的测试,所以并行性不好。另外,自底向上的单元测试也不能和详细设计、编码同步进向上的单元测试也不能和详细设计、编码同步进行。行。四)总结:相对其它测试策略而言,该测试策略四)总结:相对其它测试策略而言,该测试策略比较合理比较合理,尤其是需要考虑对象或复用时。它属于尤其是需要考虑对象或复用时。它属于面向功能的测试,而非面向结构的测试。对那些面向功能的测试,而非面向结构的测试。对那些以高覆盖率为目标或者软件开发时间紧张的软件以高覆盖率为目标或者软件开发时间紧张的软件项目来说,这
30、种测试方法不适用。项目来说,这种测试方法不适用。41 孤立测试孤立测试 一)步骤:无需考虑每个模块与其他模块之间一)步骤:无需考虑每个模块与其他模块之间的关系,分别为每个模块单独设计桩模块和驱动的关系,分别为每个模块单独设计桩模块和驱动模块,逐一完成所有单元模块的测试。模块,逐一完成所有单元模块的测试。二)优点:该方法简单、容易操作,因此所需二)优点:该方法简单、容易操作,因此所需测试时间短,能够达到高覆盖率。测试时间短,能够达到高覆盖率。三)缺点:不能为集成测试提供早期的集成途三)缺点:不能为集成测试提供早期的集成途径。依赖结构设计信息,需要设计多个桩模块和径。依赖结构设计信息,需要设计多个
31、桩模块和驱动模块,增加了额外的测试成本。驱动模块,增加了额外的测试成本。四)总结:该方法是比较理想的单元测试方法四)总结:该方法是比较理想的单元测试方法。如辅助适当的集成测试策略,有利于缩短项目。如辅助适当的集成测试策略,有利于缩短项目的开发时间。的开发时间。42 单元测试分析单元测试分析 一般可以从如下几个方面进行分析和测试一般可以从如下几个方面进行分析和测试:1 1、判断得到的结果是否正确?、判断得到的结果是否正确?对于测试而言,首要的任务就是察看一下所期对于测试而言,首要的任务就是察看一下所期望的结果是否正确,即对结果进行验证。望的结果是否正确,即对结果进行验证。432 2、判断是否满足
32、所有的边界条件?、判断是否满足所有的边界条件?边界条件是指软件计划的操作界限所在的边缘条边界条件是指软件计划的操作界限所在的边缘条件。边界条件测试是单元测试中最后也是最重要件。边界条件测试是单元测试中最后也是最重要的一项任务。在使用边界值测试的方法时,不妨的一项任务。在使用边界值测试的方法时,不妨结合实际项目参考以下测试技巧:输入了完全伪结合实际项目参考以下测试技巧:输入了完全伪造或者和要求不一致的数据。造或者和要求不一致的数据。1 1)输入一个格式错误的数据。)输入一个格式错误的数据。2 2)提供一个空值或者不完整的值。)提供一个空值或者不完整的值。3 3)与意料之中的值相差很远的值。)与意
33、料之中的值相差很远的值。44 4)假如一个列表中不允许有重复的数值存在,就可以给它)假如一个列表中不允许有重复的数值存在,就可以给它传入一组存在重复数值的列表;如果某个字段的值要求唯一传入一组存在重复数值的列表;如果某个字段的值要求唯一,那么可以输入两个或多个相同的数值来进行测试。,那么可以输入两个或多个相同的数值来进行测试。5 5)假如一个列表中不允许有重复的数值存在,就可以给它)假如一个列表中不允许有重复的数值存在,就可以给它传入一组存在重复数值的列表;如果某个字段的值传入一组存在重复数值的列表;如果某个字段的值 要求唯一要求唯一,那么可以输入两个或多个相同的数值来进行测试。,那么可以输入
34、两个或多个相同的数值来进行测试。6 6)如果要求按照一定的顺序来存储一些数据,那么可以输如果要求按照一定的顺序来存储一些数据,那么可以输入一些顺序打乱的数据来做测试。入一些顺序打乱的数据来做测试。7 7)对于一些做了安全限制的部分,尽量通过各种途径尝试)对于一些做了安全限制的部分,尽量通过各种途径尝试能否绕过安全限制的测试。能否绕过安全限制的测试。8 8)如果功能的启用有一定的顺序限制,就用和期望不一如果功能的启用有一定的顺序限制,就用和期望不一致的顺序来进行测试。致的顺序来进行测试。45 3 3、分析能否使用反向关联检查?、分析能否使用反向关联检查?在实际程序中,有一些方法可以使用反向的逻辑
35、关系来在实际程序中,有一些方法可以使用反向的逻辑关系来验证它们。验证它们。4 4、分析是否能使用其他手段来交叉检查一下结果?、分析是否能使用其他手段来交叉检查一下结果?一般而言,对某个值进行计算会有一种以上的算法,但一般而言,对某个值进行计算会有一种以上的算法,但我们会因考虑到运行效率或其他方面的原因而选择其中的一我们会因考虑到运行效率或其他方面的原因而选择其中的一种。种。5 5、分析是否可以强制一些错误发生?、分析是否可以强制一些错误发生?在实际使用过程当中,总会有意想不到各种各样的情况在实际使用过程当中,总会有意想不到各种各样的情况和错误发生。和错误发生。46 6 6、分析模块接口、分析模
36、块接口 数据在接口处出错就好像丢掉了进入大门的钥匙,无法进数据在接口处出错就好像丢掉了进入大门的钥匙,无法进行下一步的工作,只有在数据能正确流入、流出模块的前提行下一步的工作,只有在数据能正确流入、流出模块的前提下,其他测试才有意义。下,其他测试才有意义。7 7、分析局部数据结构、分析局部数据结构 局部数据结构往往是错误的根源,对其检查主要是为了保局部数据结构往往是错误的根源,对其检查主要是为了保证临时存储在模块内的数据在程序执行过程中完整、正确,证临时存储在模块内的数据在程序执行过程中完整、正确,因此应仔细设计测试用例。因此应仔细设计测试用例。8 8、分析独立路径分析独立路径 在模块中应对每
37、一条独立执行路径进行测试,单元测试的基在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。本任务是保证模块中每条语句至少执行一次。9 9、分析出错处理是否正确分析出错处理是否正确 一个好的设计应能预见各种出错条件,并进行适当的出错一个好的设计应能预见各种出错条件,并进行适当的出错处理,即预设各种出错处理通路。处理,即预设各种出错处理通路。47v 单元测试,就是针对代码单元的独立测试。单元测试,就是针对代码单元的独立测试。v 代码的基本特性决是对数据分类处理。代码通常代码的基本特性决是对数据分类处理。代码通常会有很多的判定。一个判定,就是一次分类。嵌会有很
38、多的判定。一个判定,就是一次分类。嵌套的判定,会使分类次数的翻倍。套的判定,会使分类次数的翻倍。4849 如果我们在写代码的时候,有一个分类漏掉如果我们在写代码的时候,有一个分类漏掉了,就会产生一个了,就会产生一个Bug;如果一个分类,虽然写;如果一个分类,虽然写了代码,但是处理不正确,也会产生一个了代码,但是处理不正确,也会产生一个Bug。一个函数要没有错误,必须做到两点:一个函数要没有错误,必须做到两点:1,对数,对数据的分类必须完整;据的分类必须完整;2,每一个分类的处理必须,每一个分类的处理必须正确。做到了这两点,就可以说,代码的功能逻正确。做到了这两点,就可以说,代码的功能逻辑是正确
39、的。辑是正确的。5051v单元测试的基本方法就是:依数据的分类列出单元测试的基本方法就是:依数据的分类列出输入,执行被测试程序,然后,判断输出是否输入,执行被测试程序,然后,判断输出是否符合预期。符合预期。5253测试难点 测试简单独立的代码很容易,但要在实际工作中做测试简单独立的代码很容易,但要在实际工作中做好单元测试却很困难。好单元测试却很困难。企业在实施单元测试时,通常会面对四大问题企业在实施单元测试时,通常会面对四大问题 v不愿做:程序员没有单元测试习惯。不愿做:程序员没有单元测试习惯。v没时间:编写测试代码需要耗费大量的时间,项目的周没时间:编写测试代码需要耗费大量的时间,项目的周期
40、可能不允许。期可能不允许。v 做不了:代码具有较高的耦合性,使单元测试难以进行做不了:代码具有较高的耦合性,使单元测试难以进行。v 做不好:测试效果不能令人满意。我们通常会以覆盖率做不好:测试效果不能令人满意。我们通常会以覆盖率来衡量测试效果,但要实现高标准的测试覆盖很困难。来衡量测试效果,但要实现高标准的测试覆盖很困难。54单元测试用例v一个典型的测试用例完成以下工作:设定输入数据一个典型的测试用例完成以下工作:设定输入数据、执行程序、验证输出是否符合预期。、执行程序、验证输出是否符合预期。v函数的输入数据函数的输入数据 A、参数;、参数;B、成员变量,只考虑函数需要读取的成员变量;、成员变
41、量,只考虑函数需要读取的成员变量;C、全局变量,只考虑函数需要读取的全局变量;、全局变量,只考虑函数需要读取的全局变量;D、内部输入,主要是调用子函数产生的输入、局、内部输入,主要是调用子函数产生的输入、局部静态变量、中断产生的输入。部静态变量、中断产生的输入。E、其他数据,如函数需要读取文件或数据库中的、其他数据,如函数需要读取文件或数据库中的数据,则要先在文件或数据库中设置好这些数据。数据,则要先在文件或数据库中设置好这些数据。55输入数据设计 输入可分为三大类:正常输入,边界输入,非输入可分为三大类:正常输入,边界输入,非法输入。法输入。每大类还可再分为若干小类,划分小类的依每大类还可再
42、分为若干小类,划分小类的依据是:同一小类中每个数据都具有等价的测试效据是:同一小类中每个数据都具有等价的测试效果,也就是说,小类中取任取一个数据作为输入果,也就是说,小类中取任取一个数据作为输入,如果测试通过,可以肯定同小类的其他输入也,如果测试通过,可以肯定同小类的其他输入也可以测试通过,这就是平常说的可以测试通过,这就是平常说的“等价类法等价类法”。56 正常输入 例如字符串的例如字符串的Trim函数,功能是将字符串函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前后的空格去除,那么正常的输入可以有四类:前面有空格;前面有空格;后面有空格;后面有空格;前后均有空格;前后均有空
43、格;前后均无空格。前后均无空格。57边界输入 上例中空字符串可以看作是边界输入。上例中空字符串可以看作是边界输入。再如一个表示年龄的参数,它的有效范围是再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:,那么边界输入有两个:0和和100。58非法输入 垃圾数据或使代码不能完成正常功能的数据垃圾数据或使代码不能完成正常功能的数据,如一个文件操作的函数,非正常输入有这么,如一个文件操作的函数,非正常输入有这么几类:几类:文件不存在;文件不存在;目录不存在;目录不存在;文件正在被其他程序打开;文件正在被其他程序打开;权限错误。权限错误。59预期输出 A、返回值;、返回值;B、输出
44、参数;、输出参数;C、成员变量,只考虑函数所改写的成员变、成员变量,只考虑函数所改写的成员变量;量;D、全局变量,只考虑函数所改写的全局变、全局变量,只考虑函数所改写的全局变量;量;E、内部输出,即需判断的中间结果,如函、内部输出,即需判断的中间结果,如函数计算好一个报文后发送出去,要判断这个报数计算好一个报文后发送出去,要判断这个报文是否正确。文是否正确。F、其他数据,如函数改写文件或数据库中、其他数据,如函数改写文件或数据库中的数据,也是一种输出,不过通常难于自动判的数据,也是一种输出,不过通常难于自动判断是否符合预期,可用人工查看来代替。断是否符合预期,可用人工查看来代替。60 单元测试
45、用例设计单元测试用例设计 单元测试用例的设计既可以使用白盒测试也可以单元测试用例的设计既可以使用白盒测试也可以使用黑盒测试,但以白盒测试为主。使用黑盒测试,但以白盒测试为主。白盒测试进入的前提条件是测试人员已经对被测白盒测试进入的前提条件是测试人员已经对被测试对象有了一定的了解,基本上明确了被测试软件试对象有了一定的了解,基本上明确了被测试软件的逻辑结构。的逻辑结构。黑盒测试是要首先了解软件产品具备的功能和性黑盒测试是要首先了解软件产品具备的功能和性能等需求,再根据需求设计一批测试用例以验证程能等需求,再根据需求设计一批测试用例以验证程序内部活动是否符合设计要求的活动。序内部活动是否符合设计要
46、求的活动。61 测试人员在实际工作中至少应该设计能够覆盖如测试人员在实际工作中至少应该设计能够覆盖如下需求的基于功能的单元测试用例:下需求的基于功能的单元测试用例:测试程序单元的功能是否实现;测试程序单元的功能是否实现;测试程序单元性能是否满足要求(可选);测试程序单元性能是否满足要求(可选);是否有可选的其它测试特性,如边界、余量是否有可选的其它测试特性,如边界、余量、安全性、可靠性、强度测试、人机交互界面测、安全性、可靠性、强度测试、人机交互界面测试等。试等。62 无论是白盒测试还是黑盒测试,每个测试用例无论是白盒测试还是黑盒测试,每个测试用例都应该包含下面都应该包含下面4 4 个关键元素
47、:个关键元素:(1)(1)被测单元模块初始状态声明,即测试用例的开被测单元模块初始状态声明,即测试用例的开始状态(仅适用于被测单元维持了调用中间状态始状态(仅适用于被测单元维持了调用中间状态的情况的情况);(2)(2)被测单元的输入,包含由被测单元读入的任何被测单元的输入,包含由被测单元读入的任何外部数据值;外部数据值;(3)(3)该测试用例实际测试的代码,用被测单元的功该测试用例实际测试的代码,用被测单元的功能和测试用例设计中使用的分析来说明,如:单能和测试用例设计中使用的分析来说明,如:单元中哪一个决策条件被测试;元中哪一个决策条件被测试;(4)(4)测试用例的期望输出结果(在测试进行之前
48、的测试用例的期望输出结果(在测试进行之前的测试说明中定义)。测试说明中定义)。63单元测试用例设计步骤以下描述进行测试用例设计的以下描述进行测试用例设计的6 6步通用过程。步通用过程。步骤步骤1 1:首先使被测单元运行;:首先使被测单元运行;这个阶段适合的技术有:这个阶段适合的技术有:模块设计说明导出的测试模块设计说明导出的测试 对等区间划分对等区间划分64步骤步骤2 2:正面测试:正面测试(Positive Testing)(Positive Testing)这个阶段适合的技术:这个阶段适合的技术:设计说明导出的测试设计说明导出的测试 对等区间划分对等区间划分 状态转换测试状态转换测试步骤步
49、骤3 3:负面测试:负面测试(Negative Testing)(Negative Testing)适合的技术有:适合的技术有:错误猜测错误猜测 边界值分析边界值分析 内部边界值测试内部边界值测试 状态转换测试状态转换测试65 步骤步骤4:4:模块设计需求中其它测试特性用例设计模块设计需求中其它测试特性用例设计 适合的技术:设计说明导出的测试适合的技术:设计说明导出的测试 步骤步骤5 5:覆盖率测试用例设计:覆盖率测试用例设计 适合的技术:适合的技术:分支测试分支测试 条件测试条件测试 数据定义使用测试数据定义使用测试 状态转换测试状态转换测试 步骤步骤6 6:测试执行:测试执行 66 步骤步
50、骤7 7:完善代码覆盖:完善代码覆盖 适合的技术:适合的技术:分支测试分支测试 条件测试条件测试 设计定义设计定义试验测试试验测试 状态转换测试状态转换测试 675.5调试与评估单元测试通过的一般准则单元测试通过的一般准则:(1)软件单元功能与设计需求一致软件单元功能与设计需求一致(2)软件单元接口与设计需求一致软件单元接口与设计需求一致(3)能够正确处理输入和运行中的错误能够正确处理输入和运行中的错误(4)在单元测试中发现的错误已经得到修改并且通在单元测试中发现的错误已经得到修改并且通过了测试过了测试(5)达到了相关的覆盖率标准达到了相关的覆盖率标准(6)完成了软件单元测试报告完成了软件单元