软件测试理论—单元测试课程内容为什么做单元测试单元测试的概念和内容如何做单元测试单元测试的难点和对策程序员的难题开发的模块出现问题,很难定位,已经熬了几个通宵了!!!怎么办?刚改正了一个BUG,过没几天,又发现了新问题!!!程序总在出问题,联调了几个月,还是问题不断!!!高质量的程序高质量的程序取决于以下几个方面:高质量的设计规范的编码有效的测试程序员的职责我是程序员,除了编码我还需做些什么?程序员的职责传统的开发观念?1.开发人员的任务是完成编程,让系统正确运行起来。2.程序调试通过任务就完成了。3.自信自己的程序不会出错。实际:1.开发人员的任务是完成程序,直到交付和维护。2.人的失误是不可避免的,无论多小心,都会有错误。小插曲你以前做过程序开发工作么?你是怎样自测的?效果如何?现实中的发现编码阶段引入的缺陷远远多于其它阶段系统测试发现的缺陷大多数是编码缺陷测试版本频繁,测试和项目进度被无休止的拖延。Why?开发部的压力现状:一个承担多个角色的团队参与或部分参与高层设计;承担低层设计;程序实现;承担低层测试;设计编码测试开发部的测试效果不好:为什么?没有时间测试不知道怎样测试不好组织缺乏方法和工具这种情况下,往往把单元测试的任务堆积到系统测试阶段问题如果把单元测试的任务堆积到系统测试阶段,将会怎样?大量的故障堆积在项目中后期:项目后10%的工作,占用了项目90%的时间。故障难以定位故障飘忽不定开发、测试人员疲于奔命软件缺陷的修复费用单元测试(why)最高的成本收益比减少联调和后续测试的时间BUG更容易定位更有信心去修改老代码业界平均水平商业软件单元测试工作量/总工作量=8.3%编码工作量/总工作量=16.6%军工软件单元测试工作量/总工作量=10.1%编码工作量/总工作量=18.1%业界标杆单元测试(25%)审查评审(20%)设计(17%)编码(14%)需求(7%)系统测试(4%)计划和跟踪(4%)发布后缺陷0.06Defects/KLOC单元测试发现的缺陷密度:31defects/KLOC主题内容1.为什么做单元测试2.单元测试的概念和内容3.如何做单元测试4.单元测试的难点和对策单元是什么?(IEEE)软件单元指软件设计说明中一个可独立测试的元素,是程序中一个逻辑上独立的部分,它不能再分解为其他软件成分。(实践中)软件单元指软件源代码中单个的函数,源文件或类。单元测试是什么?单元测试,对单个的软件单元或者一组相关的软件单元所进行的测试,是代码级的测试。Unit:函数,源代码文件,类把测试比作是清洗一台机器:系统测试就是清除机器外面的尘土。集成测试就是保证机器各个部件的接头处干净。单元测试就是清洗各个零件的内部。单元测试应用输入潜在错误对象单元测试测试一个类Thatiseasy!单元测试原则应该尽早地进行软件单元测试。应该保证单元测试的可重复性。尽可能地采用测试自动化的手段来支持单元测试活动。单元测试内容单元功能测试单元接口测试单元局部数据结构测试单元中重要的执行路径测试单元的各类错误处理路径测试单元边界条件测试单元测试内容开发测试设计评审代码走查单元测试集成测试面向单元的白盒测试(单元覆盖率测试)狭义的单元测试内容面向单元的黑盒测试(单元功能测试)内存和运行错误分析(内存泄漏、越界,异常)代码运行性能profile(函数效率和瓶颈分析)单元测试(who)单元测试可以是开发者本人执行,也可以是独立的专业测试人员执行。两者各有优势。建议开发人员必须完整地做单元测试,同时测试人员针对重点模块实施独立的单元测试。主题内容1.为什么做单元测试2.单元测试的概念和内容3.如何做单元测试4.单元测试的难点和对策单元测试过程单元测试过程包括8个活动:确定单元测试计划确定待测特性制订单元测试规程设计测试套件构建测试套件执行测试套件检查终止条件评估测试结果确定单元测试计划确定单元测试范围尽可能争取完全地覆盖(原则上应该做到完全覆盖)参考:通常以下情况必须安排单元测试:a)新模块b)新增代码比例超过20%c)核心模块确定单元测试计划单元测试充分性要求例如:语句行覆盖率=100%;分支覆盖率〉85%测试覆盖率要求是测试充分性的一个方面,除此之外,在单元测试中还应考虑每个软件特性的测试覆盖,如函数性能。确定单元测试计划确定终止条件确定单元测试过程的正常终止条件。该终止条件应该包括了对测试充分性要求的满足。(100%代码行覆盖,85%分支覆盖)识别可能造成单元测试过程异常终止的条件(如发现重大的设计错误、到达进度期限等)。确定单元测试计划确定单元测试资源估算进行测试活动所需的资源。应考虑测试人员、硬件、通信或系统软件、测试工具和其它资源。识别需要进行准备或申请的资源(如定制的测试工具),并做出相应的安排。指明总体进度计划基于资源和项目计划等方面的要求,确定单元测试活动的总体进度计划。确定待测特性研究待测特性要从研究单元的需求开始功能需求、非功能需求(如性能或设计约束等)、与待测单元相关的任何使用或操作过程单元的状态识别针对状态机测试单元的数据特性识别单元的输入输出数据分析以上研究分析对于制定单元测试方案和指导测试用例的设计很重要待测特性分析过程中还有可能发现单元需求上的缺陷。制定单元测试规程输入单元测试计划、待测特性分析结果、项目总体进度计划识别可重用技术(待查)通过待测特性分析,可从用例库中识别出可以重用的测试用例和测试规程,以减少重复工作。资源详细列举单元测试所需资源,包括人员、设备、工具、环境等进度计划详细的进度计划,包括风险分析和应对措施规程评审设计测试套件测试套件测试用例、脚本、驱动、桩、测试数据测试规程和测试用例的开发目前测试规程和测试用例是合一的。开发过程中在重用的基础上新增和修改。结合待测单元特性分析,充分考虑测试用例的覆盖率。测试工具的设计自研测试工具的设计要充分考虑可重用性,不同项目间通用性一般较小,统一项目不同版本间一定要具备通用性。测试规程/用例的评审单元测试数据单元测试设计中,测试数据的设计是很关键的,同样的测试规程,不同的测试数据,可能会达到不同的测试结果。a)正常数据:在测试中所用的正常数据的量是最大的,而且也是最关键的。少量的测试数据不能完全覆盖需求,但我们要从中提取出一些具有高度代表性的数据作为测试数据,以减少测试时间。b)边缘数据:边缘测试是界于正常数据和错误数据之间的一种数据。它可以针对某一种编程语言、编程环境或特定的数据库而专门设定。边缘数据要靠测试人员的丰富经验来制定。c)错误数据:显而易见,错误数据就是编写与程序输入规范不符的数据从而检测输入筛选、错误处理等程序的分支。构建测试套件测试数据的准备测试工具的开发/调试构建测试环境执行测试套件运行测试确定测试结果,处理测试过程中的异常对每个测试用例,确定单元是否通过测试。对异常进行分析,并根据情况处理:情况1:测试用例或测试数据的问题。修正并重新运行。情况2:测试规程执行的问题。重新运行。情况3:测试环境的问题。纠正测试环境并重新运行;或者异常终止测试,并汇报记录异常终止原因。情况4:单元实现中的故障。纠正单元的故障,并运行所有的测试;或者异常终止测试,并汇报记录异常终止原因。情况5:单元设计中的故障。纠正单元设计和实现中的故障,必要时修改测试设计和测试数据,并重新运行所有的测试。检查终止条件测试充分性检查检查是否达到覆盖率要求,包括测试用例执行/通过覆盖率和被测单元代码/分支覆盖率。以及其它测试充分性要求。异常终止条件检查补充测试套件以上条件不满足时,则需要补充测试套件,继续进行测试。评估测试结果按照单元测试报告模块出具单元测试报告如有必要对单元测试报告进行评审将所有测试相关工作产品纳入配置管理主题内容1.为什么做单元测试2.单元测试的概念和内容3.如何做单元测试4.单元测试的难点和对策参见的单元测试的难点没有时间做单元测试单元测试责任人不清楚测试代码难以管理覆盖率难以手工统计故障报告形式驱动和桩编写困难(可测试性)对策:没有时间做单元测试单元测试计划在项目计划应该有体现编写代码之前或同时,先设计测试用例。每个软件单元应该有什么功能?是否每个功能都有测试用例来验证它?对策:单元测试责任人不清楚强调单元测试必须由类包的设计者负责编写,因为只有这样,测试才能保证对象的运行时态行为符合需求。让测试人员或第三方人员编写测试用例,将花费更多的工作量。(201)执行测试用例可以让测试人员或自动构造系统。对策:测试代码难以管理采用测试工具管理测试代码如XUnit、C++Test、RTRT配置管理中建立配置项如,不同模块的一组代码,建立相应测试代码目录和配置项对策:覆盖率难以手工统计利用各种工具PureCoverage(C/C++/Java/.Net,Windows/UNIX)RTRT(C/C++/Java/Ada,嵌入式系统)C++Test(C/C++,Windows/UNIX)Discover(Delphi,Windows)对策:故障报告形式各种工具一般都会生成测试报告XUnit测试用例执行报告RTRT、C++Test各种综合报告(测试用例执行结果、测试用例覆盖率、内存检查和性能)对策:驱动和桩编写困难(可测试性差)通常情形下,测试驱动难以编写,测试难以进行由以下几方面原因导致:1、被测试对象需要传入的参数过多。2、内部的逻辑判断过多(内部牵扯复杂)。3、和界面显示部分交互过于频繁(耦合性太强)。4、被测对象过多的调用了其他类或方法。5、需要构造的作为参数的对象本身过于复杂解决:提高可测试性1、首先最重要的是坚持测试驱动设计(测试先于设计)的方法。优先编写测试代码。这是标准的XP方法。这不是说您应该一次性编写全部测试代码后,再一次性全部实现。对一些单元接口,编写一些测试代码,实现它们,再编写一些测试代码,再实现它们等等是个更好的办法。设计以这种方式得以进展;在实现阶段捕捉错误并在下一组测试中改正它。2、功能分解类:把功能分解到细粒度,提倡小类。方法:尽量做到每个操作对应一个方法,使方法小型化。功能分解促进:提高重用性,降低耦合度3、分层原则。对于显示部分(GUI),尽量做到显示与控制分离。把代码移到GUI视图的外面。然后各种GUI动作就能成了模型上的简单方法调用。这样,对GUI测试者来说,通过方法调用测试功能比间接地测试功能容易的多。另一个好处是它使修改程序功能而不影响视图变的更容易。解决:提高可测试性4、抽象我们可以想出各种各样的办法来降低耦合程度,但是归纳起来,不外乎增加抽象的层次来隔离不同的类,这个抽象层次可以是具体的类,也可以是接口。GOF的23种设计模式,没有一种模式的思路不是从增加抽象层次入手来解决问题的5、对于可能要作为参数的复杂类,可以做一个接口,用接口说明外部程序组件使得我们可以容易地在测试案例中模拟这些组件。当需要时可以实现按接口生成一个模拟类作为参数传入。特别是当该类还没有完全实现时,这种方法最为行之有效。解决:提高可测试性6、如果自己不负责测试工作,作为开发员在设计过程中要时刻提醒自己“我如何才能测试这些代码?我如何才能以可测试方式编写这些代码”。7、重构是提高可测试性的主要手段单元测试经验测试驱动开发,开发以测试为导向写不出测试用例,就谈不上编写单元代码开发一个单元的代码的步骤:1.设计和编写测试它的用例代码2.运行自动测试,检查是否发生错误3.编写单元的代码4.使用前面的用例回归测试它单元测试是编码的一部分!单元测试经验测试驱动开发编写单元测试用例促进解除模块之间的耦合。先编写测试用例,强迫自己从利于调用者的角度来设计单元,关注单元的接口。为了便于调用和独立测试,必须降低单元和周边环境的耦合程度,单元的可测试性得到加强,模块化程度得到提高。这样单元的可重用性也容易被考虑和提高。单元测试经验重构测试用例数量是逐步增加