UML软件工程组织

单元测试工具Visual Unit 简明教程
作者: UnitWare
  Visual Unit,简称VU,是新一代单元测试工具,功能强大,使用简单,完全可视化,不需编写测试代码。VU的测试结果使程序行为一目了然,有助于整理编程思路,提高编程效率和正确性,并能快速排错;VU还增强调试器功能(如自由后退、用例切换),提高调试的效率;VU能达到空前的测试完整性,轻松完成语句、条件、分支及路径覆盖;VU提供详尽的测试报告...... VU不仅是单元测试工具,更是一种使程序开发变得更高质更高效更舒适的工具。VU目前版本适用于C++语言。

  在现有开发队伍和管理水平的基础上,使用VU进行充分的单元测试,可以使项目或产品的质量较大幅度地提高,同时开发成本还要较大幅度地下降。

  使用VU,黑盒方面,可以轻松完成功能测试、边界测试、速度测试,白盒方面,可以轻松完成语句覆盖、条件覆盖、分支覆盖、路径覆盖。这种空前的测试完整性,使代码中的缺陷无所循形。

  使用VU,随时可以用回归测试检验修改是否引入新的错误,因此,随时可以对项目的设计进行或大或小的修改,轻松进行螺旋式的迭代开发,或边开发边设计,甚至“以开发代替设计”,使项目或产品真正符合用户的需求。

  VU功能强大但使用简单,学习资料丰富,一天时间就能轻松上手;在VU的支持下编程,程序行为一目了然,感觉舒适有趣,很受程序员的喜爱,决不会受到开发人员的抵制;VU提供详尽的测试报告,测试部门可以依据测试报告对测试结果进行审核,保证测试质量。

  运行环境与安装卸载

  操作系统:

  Windows2000, Windows XP, Windows Server 2003。

  内存:

  64M,推荐128M。

  硬盘空间:

  50M。

  开发环境:

  VC6.0、VC.NET、VC.Net 2003、C++ Builder6.0。

  安装VU:

  解包后运行Setup.exe文件,按提示完成安装。

  VU是绿色软件,安装时不写注册表,除两个DLL文件拷贝到系统目录下外,全部文件均在安装目录下。

  启动VU:

  安装完后,从开始菜单启动VU。

  卸载VU:

  从开始菜单卸载。

  VU1.0 主要界面  控制窗口


  主窗口


  信息窗口及其菜单


  数据窗口及其菜单


  代码窗口及其菜单


  路径窗口及其菜单


  测试用例编辑器


  测试用例设计器


  测试报告

  建立与配置测试工程

  建立测试工程:

  测试工程使用与产品工程相同的开发环境建立和编译,运行测试工程即可执行测试,例如,产品工程的开发环境是VC6.0,则同样用VC6.0建立、编译测试工程。

  对测试工程的要求是:能编译被测试文件,且编译链接的结果是可直接执行的文件,在符合这些条件的前提下尽可能简单,例如,产品工程是VC6.0的MFC Multiple Document工程,则可以采用MFC Dialog Base作为测试工程,它比较简单,并且可以编译MFC文件,但不能使用Win32 Application,因为它不能编译MFC文件,也不能使用MFC DLL,因为它的编译链接的结果不是可直接执行的文件。

  多个产品工程可以使用一个测试工程,因此,建议采用较高适应性的工程类别,例如,产品工程是Win32 Application,测试工程还是采用MFC Dialog Base为好,如果以后项目中要开发一个MFC工程,可以附加进来一起测试。

  测试工程的命名建议采用"Test"+产品工程名,如TestDemo。特别提醒:测试工程不能命名为:xxxTester,因为这是测试文件的专用命名格式。

  配置测试工程:

  测试工程与普通的产品工程具有两个不同之处:

  1)定义编译条件_VUNIT。VU提供的支持代码中凡是要用在产品文件中的宏,都只在定义了编译条件_VUNIT时才编译,在产品工程中不编译。

  2)执行VuxRunTest()函数。在测试工程最早执行的代码中调用这个函数,这个函数执行完毕,测试也就结束。

  除上述两点外,测试工程与产品工程区别不大,在不同的开发环境,具体的配置略有区别,请按照帮助系统的说明进行。

  生成测试文件

  生成测试文件:

  在控制窗口中选择要测试的文件。

  VU会自动弹出“生成测试文件”窗口,点击“确定”即可生成测试文件。

  生成测试文件后,将被测试文件及其引用的文件、刚生成的测试文件加入到测试工程。

  在被测文件中添加代码:

  在被测试文件中添加代码并不是必须的,但这些代码将提供重要的功能:

  UINT_TEST宏:功能是定义友元,使测试代码可以访问类的私有或保护成员。

  TEST_DUMP宏:这是一组宏,格式与VC60的消息映射宏相似,功能是为自定义数据类型输出成员变量的数值。

  VU提供了自动生成这些代码的工具,只需将生成的代码拷贝到指定位置即可:

  (控制窗口)“定义数据输出”按钮,弹出“定义数据输出”属性表,在“自定义数据类型”页,左边的输入框中输入类名/基类名/成员变量,将右边生成的代码拷贝到被测试文件,如下图。

 

  只有基类也是自定义类型并且已定义了TEST_DUMP宏,才需输入基类名。

  生成测试函数

  
选择了被测试文件后,文件中包含的需要测试的函数会出现在函数列表中,可以选择任一个要测试的函数。

  如果选中的被测试函数不存在对应的测试函数,自动弹出“生成/匹配测试函数”对话框,可以选择是否生成边界测试代码和速度测试代码,建议采用默认值。点击“确定”,VU在测试文件中生成测试函数。

  生成测试函数后,会自动弹出测试用例编辑器。绝大多数情况下,通过测试用例编辑器即可处理测试用例的建立与编辑等工作,无须查看或编辑测试函数的代码。

  编辑功能测试用例

  根据函数最典型的功能,在测试用例编辑器中编辑第一个测试用例并编译执行测试工程,即可运行测试。

 

 

  输入数据和预期输出可以用点操作符访问成员变量,甚至调用成员函数。

  VU只生成第一个测试用例。由于不同的测试用例之间,往往变化很小,例如只有一个输入数据和一个预期输出不同,所以,在现有的测试用例的基础上进行修改是新建更多测试用例的最高效的方法。点击“新建”按钮,VU就会生成当前选中用例的拷贝,并选中新生成用例,这时即可进行修改以获得新的测试用例。

  点击“代码模式”按钮,会转换成代码模式,显示测试用例代码。可以对代码进行编辑,有些测试用例比较特殊,例如连续操作的测试用例,即重复调用被测试函数的测试用例,或异常测试用例,可以通过编辑测试用例的代码来获得。

  一边编写代码一边测试

  编写函数声明与定义后就可以生成测试代码:

  在头文件编写函数声明,在源文件编写空的函数实现,有返回值可以随便加一个返回语句,通过编译后就可以生成对应的测试函数。

  生成测试代码和编辑第一个测试用例:

  从函数列表选中被测试函数,生成测试函数,VU会自动弹出测试用例编辑器。

  根据函数最典型的功能,填写第一个测试用例的输入数据与预期输出,编译并运行测试工程,VU主窗口会自动弹出,显示测试结果。

  一边编码,一边测试,完成功能覆盖:

  为函数的每个功能点新建测试用例。

  编写函数代码使所有测试通过。

  也可以先编写代码,每完成一个功能点即添加测试用例来测试它。

  程序员在编码时当然需要了解程序的功能,也就是说,要了解程序在不同的输入时应该产生什么样的输出,这些就是功能测试用例。

  随时观察程序的行为:

  随时可以通过运行测试来观察程序的行为,例如,编写了计算某一个变量VAR的几行代码,可以用TEST_TRACE(VAR)宏来输出它的数值,看看结果对不对。观察程序行为对整理编程思路,提高编程效率和正确性具有重要意义,后面会进一步描述。

  快速排错:

  测试通不过时,大部分情况下都无须单步调试即可找出错误原因,后面会进一步描述。

  高效调试:

  需要单步调试时,在VU的支持下调试,可以大幅度提高调试效率,后面会进一步描述。

  代码优化:

  代码编写完成并进行功能测试后,阅读代码,修改可读性不强的代码、重复的代码、意图不清晰的代码、或其他不满意的代码。给代码添加必要的注释。

  每完成一个小的改动,就重新运行测试,以确认代码的功能未改变。

  全面测试:

  完成白盒覆盖:语句覆盖、条件覆盖应达到100%,删除不可达分支后,分支覆盖也要达到100%,删除安全的分支或分支树后,路径覆盖也要达到100%。

  打开边界测试开关,运行边界测试,可在数据窗口观察输入边界值时函数的输出。

  打开速度测试开关,运行速度测试。

  关于白盒覆盖测试用例的设计、边界测试与速度测试,后面会进一步描述。

  观察程序行为

  
程序的行为,无非就是在一定的输入时,产生了什么输出、执行了哪些代码、执行的路径是什么,这些,都可以一目了然地从主窗口的各子窗口观察到。对程序行为了然于胸,不但有助于整理编程思路,提高编程效率和正确性,也会使编程工作变得更有趣和更舒适。

 

 

  快速排错

  观察程序行为还可以实现快速排错。对比预期输出与实际输出,阅读执行代码,很容易找到错误原因。对某些关键数据,还可以使用TEST_TRACE宏输出中间结果。在很多时候,预期输出本身是错的。下例中把result = 0; 改为result = 1;后,测试仍然是失败的,因为预期输出不是625而是3125。

  快速排错可以节约很多时间,但它是事后的静态分析,如果找不到错误所在,仍然需要进行单步调试。

  高效调试

  开始调试:

  (控制窗口)点击“调试”开关,用调试方式运行测试工程。如下图(VC60)


  自动断点:

  程序自动中断时,执行调试器的“Step Into”(VC)或“Trace Into”(C++Builder)命令两次或三次。C++Builder可能会弹出CPU窗口,直接关掉。自动断点可以关闭:(控制窗口)->选项->扩展,在“忽略自动断点”前打上勾。

  后退与重复:

  使用调试器的“Run to Cursor”功能,可以实现真正的后退。跟踪时过了头或到了函数结束还没有找到错误所在,可以单击函数开始处的代码,然后点击“Run to Cursor”,即可重新跟踪,可以多次重复,一直到调试结束才退出调试。

  后退是由VU的测试代码控制的,实现的原理是“重来”,参数和成员变量的值会重新设置,可算是真正的后退。

  后退也使调试器的“编辑继续”功能真正有效,修改代码后,从函数入口处重新单步执行,看到的就是修改后的执行结果。

  用例切换:

  通过切换用例,可以比较不同输入时代码的行为或变量的值。在VU的主窗口中切换当前用例,然后执行调试器的“Run to Cursor”回到函数的入口,即可切换用例。

  完成调试后,要关闭VU的调试开关,才能继续进行测试。

  灵活运用VU提供的调试增强功能,可以大幅提高调试效率。

  完成白盒覆盖

  
功能测试常常是不够充分的,例如:真的是所有功能点都测试了吗?程序的功能点是人为的定义,常常是不全面的;各个输入数据之间,有些组合可能会产生问题,怎样保证这些组合都经过了测试?难于衡量测试的完整性是功能测试的主要缺陷,所以,完成功能测试后,要从白盒角度,即从逻辑覆盖的角度检查测试完整性,对于未覆盖的逻辑目标,要设计测试用例覆盖它,这样,可以最大限度地揪出程序中隐藏的“臭虫”。

  VU可以很轻松地完成语句覆盖、条件覆盖、分支覆盖与路径覆盖。

  代码窗口显示未覆盖语句和未覆盖条件,选中后可用快捷菜单打开测试用例设计器。

 


  路径窗口显示未覆盖分支和未覆盖路径,选中后可用快捷菜单打开测试用例设计器。



  测试用例设计器计算出一个近似用例,并生成修改提示,依据修改提示对近似用例进行简单修改,即可获得可覆盖预期逻辑目标的测试用例。

  上图中,待满足条件是 A==2 || X>1,两个条件的关系是逻辑或,即可以任选一个。如果选择条件A==2,A==2与已满足条件A>1并不冲突,因此,只需把输入数据中的A的值改为2,即可得到可覆盖预期逻辑目标的测试用例;如果选择X>1作为修改条件,由于依赖关系中出现了变量X,这时应点击“代码”按钮查看代码的依赖关系,如下图。从下图可看出,由于X被语句X=X/A重新赋值,且A的值为3,要使待满足条件X>1成立,X的输入值必须大于等于6。因此,把近似用例中X的值改为6或大于6的数,就可以得到符合预期的测试用例。修改后点击“新建用例”按钮,新用例就会保存到测试文件中,重新运行测试,就会看到逻辑目标已被覆盖。

  使用测试用例设计器设计白盒覆盖测试用例,无须象传统的方法一样分析程序的逻辑结构。在很复杂的情况下,也只需要对程序代码有基本的理解。例如下图,如果对所测试的程序有基本的理解,那么很容易看到,在strlen(head) != false,即head不是空串的前提下,不进入循环是不可能的,因此逻辑目标(分支或路径)是不可覆盖的,应在路径图中删除。

 


  边界测试与速度测试

  
边界测试,是指使用预先定义的边界值,如最大值、最小值、空值、或其他特殊值作为输入数据来运行测试。所有数据类型都可以定义边界值,包括自定义的类型,具体方法参考帮助系统。边界测试是功能测试的有效补充,通过检查程序是否对边界输入作了适当处理,可有效增强程序的健壮性。

  速度测试,通过轮流执行现有的测试用例多次(默认为共1000次)来计算函数的平均速度。

  要运行速度测试和边界测试,只需要打开开关。

 


  查看测试报告

  测试报告记录函数测试的详细结果数据。

  菜单->测试报告,打开测试报告窗口。

  测试报告含有十多项数据,不过常用的只有失败断言、逻辑覆盖率、速度等几项。可以使用“设定”功能选择显示哪些项。

  逻辑覆盖率是测试是否充分的重要指标,如果程序集成后发现不明错误,测试不充分的函数包含错误的可能比较大。

  如果程序性能不理想,可以将函数耗时由大到小排列,速度比较慢的函数可能就是性能瓶颈。

 


  回归测试

  
回归测试是指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。自动回归测试将大幅降低系统测试、维护升级等阶段的成本。回归测试包括两部分:函数本身的测试、其他代码的测试。在对被修改的函数重新测试。如果函数的设计功能没有变化,直接运行函数测试就可以了。如果修改了设计功能,则要根据增减的功能点,增加或删除测试用例。另外,还要完成白盒覆盖。

  函数代码的修改可能导致调用该函数的代码产生错误,所以需要测试其他代码。如果函数是私有函数并且未涉及到全局变量,应运行类测试,否则应运行工程测试。在函数列表中选择类测试或工程测试,编译运行测试工程,即可执行对其他代码的回归测试。

 

 

版权所有:UML软件工程组织