这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » [转帖]单元测试简介

共33条 1/4 1 2 3 4 跳转至

[转帖]单元测试简介

菜鸟
2006-12-28 02:08:56     打赏
单元测试的必要性和效益,在《单元测试思想》中已有详细叙述。简单的说,要保证软件产品质量,要避免软件项目延期,要控制软件项目预算,单元测试恐怕就是必不可少的。 如何进行单元测试呢? 即使简单代码中的简单错误,如果没有人工设立的测试用例,任何测试工具恐怕都无法自动发现,因此,建立测试用例集,人工定义程序的输入,执行程序并验证输出是否符合预期,是单元测试的最主要也是必不可少的方式。 如何编写测试代码? 一个测试用例的码应该包括如下内容: 1.建立被测试对象 2.定义输入数据 3.执行被测试函数 4.判断预期输出 5.销毁被测试对象 这种格式可以适应各种复杂的输入输出,例如,参数是复杂的数据类型、需要预先设定被测试对象的状态(给成员变量赋值)、要执行前置操作、输出要判断多个数据的值等等 这种格式的另一个好处是便于建立多个测试用例。第二个及更多的测试用例可以通过拷贝->修改输入输出的方式快速建立 在测试用例的前后加上{},这样各个测试用例自成一个域,便于使用相同的变量名 VU自动生成的测试代码就采用这种格式。 传统的单元测试方式需要耗费大量的时间:一是编写测试代码需要大量时间;二是要设计比较完整的测试用例集也要耗费大量时间,所以,单元测试最好在自动化的测试工具支持下进行。



关键词: 转帖     单元     测试     简介    

菜鸟
2006-12-28 02:09:00     打赏
2楼
VU自动生成测试代码,并自动生成输入输出数据的框架,填写数值就可以建立测试用例

多个测试用例用拷贝当前用例的方式新建,通常只须对输入数据和预期输出做简单修改即可




要人工找出所有的测试用例(所有的等价类)通常是很困难的,但使用VU,只需要为容易想到的典型的输入建立测试用例就行了,其他用例可以在测试用例设计器的帮助下轻松找出来




特殊情况下可以切换到代码模式直接编辑代码




复杂的输入输出也能轻松应对




用.操作符直接访问成员变量或调用成员函数




预期输出可以判断多个数据




只需要人工建立典型的测试用例,VU会统计白盒覆盖状况,对于未覆盖的语句、条件、分支或路径,可以用测试用例设计器来建立相应的测试用例




为未覆盖的代码、条件、分支或路径设计测试用例




根据上面的修改提示,对近似测试用例作简单修改,即可获得需要的测试用例




即使是很复杂的程序,只要对代码有基本的理解,也能轻松找出隐藏得很深的遗漏测试用例


菜鸟
2006-12-28 02:10:00     打赏
3楼


般情况下,达到100%的语句、条件、分支、路径覆盖都是很容易的,不可覆盖的分支可以在逻辑结构图上删除。非常复杂的代码,在删除不可覆盖的分支后,路
径的数量通常不会很多,仍然能够达到100%的路径覆盖,必要时还可以在逻辑结构图中屏蔽安全的分支结构以减少路径数量





统的单元测试方式下,达到100%的语句、条件、分支、路径覆盖是很困难的,但使用VU,达到了这种覆盖仍然认为测试不完整,因为,如果缺少处理某些特殊
输入的代码,任何覆盖率都不能发现,所以,VU还提供了自动边界测试来检查对特殊输入的处理,运行测试时只要打开边界测试开关就行了




这个示例中,只有2个人工设定的测试用例,现在显示有27个用例,其中25个是自动生成的边界测试用例




由于VU自动生成测试代码,人工只需要设计典型的容易想到的测试用例,所以单元测试本身费时很少。另一方面,VU还帮助程序员大量提高开发效率




编写程序的主要时间消耗并不在敲键盘,而在于编程思路和调试,使用VU,恰恰能在这两方面提高工作效率




编写一小段程序,即可执行测试,看看程序的行为。这里显示各种输入与输出,还可以用TEST_TRACE()宏输出任何变量或表达式的中间结果




这里显示当前输入时所执行的代码行




这里显示当前输入时程序的执行路径




输入输出数据、代码执行状况、路径图,三位一体,完整地描述了程序的行为,帮助验证编程思路,随时发现不正确的程序逻辑,大幅度提高编程的生产效率,同时也使编程工作变得轻松一些




多数代码错误,都可以通过浏览这些测试数据快速发现,而不需要单步调试。如果需要调试,在VU的支持下调试也会有更高的效率




打开调试开关




只要用调试方式运行测试工程,即可进入调试,程序会自动中断




在VU的支持下调试,会自动选择输入数据,并可以切换输入(即切换到其他用例),支持无限制的后退,提高调试效率




使用VU,可以轻松完成100%语句、条件、分支、路径覆盖,宏观上,还统计整体的测试状况。待测文件列表可以统计项目中含有未测试函数的所有文件,从整体上保证测试的完整性




还提供测试报表,详细地记录测试结果


菜鸟
2006-12-28 02:10:00     打赏
4楼
运行Demo测试

这里以VC6.0为例,其他开发环境也基本上是一样的,有问题请参考帮助系统





启动VU。启动开发环境,打开示例的测试工程,目录为:VU安装目录\u24320开发环境名称

设置开发环境选项:由于测试代码是由VU生成和维护的,选上这里后,当VU生成测试代码时,开发环境就会自动载入而不会报警。C++
Builder 6.0 没有类似选项。




切换到目录页,添加搜索路径,将VU目录下的Include目录加入搜索路径




把示例的产品工程也加入搜索路径,因为测试工程要编译产品工程的文件。




编译并运行测试工程,即可执行测试




测试完成,主窗口自动弹出,显示测试结果




随便选择另一个函数试一下




编译并运行测试工程




测试结束,显示测试结果


菜鸟
2006-12-28 02:10:00     打赏
5楼
建立测试工程

我们用 VU目录/Projects/
下的代码来进行演示,您可以使用这些代码进行对照练习。如果您的VU目录下没有Projects文件夹,请升级到最新版本

请用您的开发环境建立一个工程(产品工程),把示例代码拷贝到产品工程目录下,并加入工程中。如果您的产品工程不使用预编译头文件(如C++
Builder),请使用code_nph目录下的示例代码,否则请使用code目录下的示例代码




这里用VC6.0进行演示,这是新建的产品工程的目录。不同的开发环境,建立和配置测试工程的方法大同小异,请参考帮助系统《建立和配置测试工程》部分




几个示例的产品类已加入到产品工程。这里的产品工程是一个MFC工程,您也可以使用非MFC工程




现在建立测试工程

测试工程只要符合下列条件就可以了:

能编译要测试的产品代码文件

编译链接结果是可执行文件




测试工程的名称建议为:Test+产品工程名,但不要用xxxTester,因为这是测试文件的命名格式



由于产品工程是MFC工程,测试工程也应该是MFC工程,这样才能编译产品代码文件



后面就没有其他要求了,尽可能简单就是了


配置测试工程,建议直接对照帮助中的说明进行,有问题时再参考本节的演示

启动开发环境,打开测试工程。这里以VC6.0为例,其他开发环境的配置也大同小异




设置开发环境的一些选项



这里选上,当VU生成测试代码时会自动载入。VC7/VC8的该选项位置请参考帮助系统,C++
Builder 6 无此选项



添加搜索路径

VU目录/include/



产品工程目录



测试工程设置



添加编译条件_VUNIT,如果产品工程和测试工程不是MFC工程,还要另外添加编译条件_NMFC,对于C++Builder6.0,非VCL工程则要另外添加编译条件_NVCL


菜鸟
2006-12-28 02:10:00     打赏
6楼
添加执行测试的代码

这是测试执行代码,把它加在测试工程的入口中,执行这行代码后,测试结束,测试工程就可以自动退出了,也可以把return
FALSE; 改为exit(0);


VuxRunTest()在以下文件中定义:

VU目录/include/VuxRun.h

在这里包含这个文件




使用了预编译头文件的产品工程和测试工程,在预编译头文件中包含
VUnit.h 文件(包括产品工程和测试工程),不使用预编译头文件的工程,当在产品文件中添加了测试支持代码时,如果产生编译错误,在该头文件中包含
VUnit.h



在产品工程的同样位置也加上这一行



启动VU,这里使用的是个人版。配置测试工程,个人版和企业版都是一样的



设置产品工程和测试工程的目录



选择产品工程录



选择测试工程目录,注意不要选错,否则测试将不会运行



报表文件路径可以使用缺省



设置选项



看一下开发环境对不对?



如果不使用预编译头文件,要把这里清空



配置已全部完成,编译并运行测试工程,如果通过编译,弹出这个提示,表示配置正确,否则请参考帮助中编译错误方面的说明



菜鸟
2006-12-28 02:11:00     打赏
7楼
生成测试代码前的准备
为了便于说明,演示时产品工程和测试工程分别使用一个IDE实例,实际工作中可按照习惯处理,但使用IDE插件时,两者必须用同一个IDE实例





生成测试文件前,最好完成两项前期准备:


把产品文件加入测试工程并试编译;


在产品文件中加入测试支持代码。





单元测试是"隔离"的测试,只有能"隔离"的代码才能测试。对于VU来说,能"隔离"的意思,就是把产品文件加入测试工程后能通过编译。在生成测试文件前
将产品文件加入测试工程并编译,这样比较容易解决编译错误,因为这时的编译错误是一般的编译错误,通常与VU无关





现在我们想测试CMyClass类

把产品文件加入测试工程




试编译

果然有编译(链接)错误

这种错误是所引用的源文件未加入测试工程引起的



CMyClass类引用了这两个文件,把它们也加入测试工程



编译通过



为了访问私有成员和输出成员数据,还需要在产品文件中添加测试支持代码,具体来说,测试支持代码的功能是:可以测试私有或保护函数,并使测试用例可以访问
任何私有或保护的成员变量和成员函数;测试时可以输出成员变量的值,并且被测试类的对象在任何地方使用时(例如作为参数时),VU都可以输出它的值




测试支持代码只在测试工程中被编译,对产品工程包括调试版没有任何影响



测试支持代码由工具生成,人工拷贝到产品文件的指定位置中



填写类名



如果基类也添加了测试支持代码,则填写基类名,否则不要填写



填写成员变量名,每行一个,不包括数据类型



填写成员变量是为了在需要时输出它的值,如果成员变量很多,可以只填写重要的成员变量



用Ctrl+C拷贝这一行



粘贴到这个位置(头文件类体内)



用Ctrl+C拷贝这一行



粘贴到这个位置(头文件类体外)



拷贝这几行



粘贴到源文件


菜鸟
2006-12-28 02:11:00     打赏
8楼
生成测试代码

VU自动生成测试类,测试类生成后可以直接编译;自动生成测试函数,测试函数生成后自动弹出测试用例编辑器



这里打开产品文件(源文件)



当打开一个产品文件时,VU会查询是否存在对应的测试类,如果不存在,则弹出这个窗口



在生成测试文件前,最好先完成上一节所述的准备工作



已生成测试类,需手工将文件加入测试工程(使用IDE插件时会自动加入)



测试工程目录下的这两个文件就是VU刚生成的测试文件,把它们加入测试工程



从这里选择要测试的函数,如果函数不在列表中,先在源文件中编写一个空的实现





如果不存在对应的测试函数,会弹出此窗口,提示将生成测试函数





已经生成测试函数,自动弹出测试用例编辑器





填写第一个测试用例的输入数据和预期输出





编译并运行测试工程,即可执行测试

菜鸟
2006-12-28 02:11:00     打赏
9楼
测试用例编辑器入门
VU通过三个阶段完成彻底的测试:基本功能测试、白盒测试、边界测试。


第一阶段使用测试用例编辑器人工建立典型的测试用例,只需建立容易想到的测试用例,不必考虑测试是否完整;第二阶段在第一阶段的基础上,自动统计白盒覆盖
率,使用测试用例设计器,设计遗漏的测试用例,达到100%语句、条件、分支、路径覆盖;第三阶段使用预先定义的边界值自动生成测试用例,检查代码是否对
特殊输入作了适当处理





显示各个测试用例的输入数据,单击可选中一个





显示函数注释,以便了解函数功能,有助于设计测试用例





当前用例的输入数据和预期输出





各个子窗口均可以"最大化"





VU会生成第一个测试用例,由用户填写输入数据和预期输出。如果输入数据或预期输出比较复杂,在填完第一个测试用例后,最好先运行测试,以便检查录入错误





其他用例通过拷贝当前用例并修改的方式快速建立,点击这里就会拷贝当前用例,并把新的用例作为当前用例,修改输入输出即可建立新的用例





通常,输入数据和预期输出都要修改





可以移动当前用例的位置以便重排序





测试用例依据输入分为四类:正常输入、边界输入、非法输入、其他输入,从这里可以选定当前用例的类别





用不同的背景色区分用例的类别。





点击这里切换到代码模式,需要时可以直接编辑代码





点击"确定"保存测试用例集

菜鸟
2006-12-28 02:11:00     打赏
10楼
复杂参数




先看看当参数是引用、指针、指针的指针时,VU生成的测试用例是如何处理的。这个函数,它的参数分别为对象、指针、引用、指针的指针



VU生成的代码中,全部都是对象,可以直接赋值,这样处理是为了简化问题。VU在调用这些对象时,再按参数的本来类型作适当处理



这是为了处理指针的指针而生成的中间变量,不要修改它。只有最后是"="的才是可能需要赋值的



这是测试结果



现在演示当参数是高级数据类型的情形



第一个参数是对象的引用,第二个参数是对象的指针,全部都生成对象。由于VU使用pObj代表被测试对象的指针,用ret代表返回值,所以当参数名为pObj或ret时,会加一个下划线



变量名后面的"="只表示这个变量可能需要赋值,对于基本数据类型或定义了=操作符的高级类型,可以直接赋值,其他情况可以灵活处理,只要符合C++的语法就行了



对于没有构造函数或其他初始化函数的结构,用.操作符(点操作符)给各个域赋值



如果不是直接赋值,自动生成的"="可以删除,也可以置之不理



一个结构可能有很多个域,一个对象可能有很多个成员,只要为被测试函数需要读取的域或成员设定初始值就行了,不必理会其他无关的数据



有构造函数的类,则可以直接调用构造函数。调用缺省构造函数可以不作任何修改,VU会自动删除多余的"="



如果要调用构造函数CMyClass(int),则可以这样写...



这样就可以了,VU会自动删除最后的"="



也可以调用对象的其他实始化函数,例如:_pObj.Init(),总之,可以使用各种C++语法为参数设定初始值



当输入输出比较复杂时,建立第一个测试用例后,最好编译并运行测试,没有编译错误时再建立其他测试用例



这是测试结果



由于没有为结构PERSON添加测试支持代码,所以这里不能显示对象的值



CMyClass类已添加测试支持代码,所以当它的对象指针作为参数时也会输出数值,这些数据输出在实际的工作中具有相当重要的作用



现在来看一下添加更多的用例



当输入输出比较复杂时,通常只是第一个用例稍麻烦些,第二个及更多的用例一般只需要修改一两个数值



当输入输出比较复杂时,请注意以下要领:1、可以使用普通C++语法;2、只为被测试函数需要读取的域或成员设定初始值;3、建立第一个测试用例后编译并运行测试,排除编译错误后再建立其他用例。


共33条 1/4 1 2 3 4 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]