1、I目 录前 言 .1第 1 章 安装与示例 21.1 运行环境与安装 21.1.1 下载与安装 .21.1.2 运行环境 .21.1.3 编译器 .21.1.4 适用范围 .21.2 示例工程介绍 21.2.1 打开示例工程 21.2.2 用于学习基本功能的示例 .21.2. 3 用于体验 ETDD 的示例 21.2.4 执行测试 .31.3 快速体验 VU2.3第 2 章 建立工程 42.1 示例说明 42.2 建立工程 42.2.1 打开“新建工程向导” .42.2.2 模板选择 .42.2.3 导入数据 .52.2.4 常规信息 .52.2.5 设定测试任务 .62.2.6 指定头文件搜
2、索目录 .72.2.7 编译选项 .82.2.8 链接选项 .102.2.9 高级选项 .11第 3 章 常见错误与解决 133.1 解析错误 13II3.1.1 解析错误:文件xxx包含的文件xxx.h未找到 .133.2 编译错误 143.2.1 编译错误:文件未找到 153.2.2 编译错误分析 .153.2.3 解决错误的途径 .153.3 链接错误 183.3.1 符号未定 义: .183.3.2 符号重定义错误 .20第 4 章 建立用例 234.1 生成用例代码 234.2 生成用例数据 24第 5 章 测试输出及应用 285.1 测试输出窗口的操作 285.2 信息窗口 285
3、.2.1 用例数与当前用例 .295.2.2 速度测试结果 .295.2.3 白盒覆盖率 .294.2.4 测 试断言 .295.2.5 测试状态 .295.2.6 失败的测试 .295.3 数据窗口 305.3.1 数据种类 .305.3.2 显示格式 .305.3.3 最大输出条数和数据筛选 .315.3.4 切换用例 .315.4 代码窗口 315.4.1 当前用例执行了哪些代码? .315.4.2 语句覆盖、条件覆盖、MC/DC 标示 315.5 路径窗口 32III5.5.1 逻辑结构图构成 325.5.2 删除/恢复逻辑单位 325.6 测试输出的应用 335.6.1 快速排错 .
4、335.6.2 支持 ETDD33第 6 章 解决内部输入:底层模拟 346.1 底层模拟器的基本使用 346.2 底层模拟器的高级使用 396.2.1 模拟复杂数据类型 .396.2.2 多次调用同一子函数 .406.2.3 设定输出参数 .406.2.4 设定数组参数 .416.2.5 设定成员变量、全局变量的值 .416.2.6 解决难于自然取得的内部输入 .416.2.7 解决局部静态变量的用例中控制 .426.2.8 对库函数使用底层模 .42第 7 章 编辑测试代码 447.1 编辑方式 447.1.1 在用例代码窗口编辑 .447.1.2 在测试文件窗口编辑 .447.2 语法
5、447.2.1 固定变量名 .447.2.2 字符串赋值 .447.2.3 预期输出不能含有转定义双引号 .457.3 预期输出代码及其自动生成 457.4 表格化与取消表格化 477.3.1 表格化 .477.3.2 取消表格化 .477.4 编辑公共初始化代码 48IV7.5 编辑桩代码 48第 8 章 高级用例技巧 498.1 打印内部输出 498.1.1 在 VU 界面中指定 498.1.2 在产品代码中指定 .518.2 判断内部输出 518.2.1 判断内部输出的步骤 .518.2.2 判断内部输出的注意事项 .528.2.3 判断子函数返回值 .528.2.4 判断数组中的任意项
6、 .528.3 修改函数原形后匹配原用例 52第 9 章 白盒覆盖与找出遗漏用例 549.1 白盒覆盖与标示 549.2 用例设计器使用方法 549.2.1 用例设计器的用途及使用条件 .549.2.2 白盒覆盖顺序 .559.2.3 用例设计器的界面 .559.2.4 工作原理 .559.2.5 修改提示 .569.2.6 使用方法 .579.2.7 识别与删除不能覆盖的逻辑目标 .579.3 用例设计器使用示例一 579.4 用例设计器使用示例二 619.5 实现彻底测试的方法 651前 言这是 Visual Unit 3 简明教程,分为三个部分:第 1 章为第一部分,介绍 VU3 的安装
7、与示例工程;第 2-5 章为第二部分,用演示方式一步一步介绍使用 VU3 建立工程、常见错误有解决、建立用例代码和用例数据、执行测试、以及测试输出及应用,建议对照介绍,一步一步进行操作练习;第6-9 章为第三部分,介绍底层模拟、用例代码编辑、高级用例技巧、以及白盒覆盖和找出遗漏用例。 从第二部分开始,使用专为本简明教程准备的示例代码进行讲解。这些示例,是从 VU 示例工程抽取的一些文件,为了使实际工作中比较常见的问题得于出现,作了一些修改:使用了编译条件_MY_DEFINE;将 cstr.c 文件的源代码移到静态库中。您可以在以下目录拷贝这些示例代码:VU安装目录SamplesDemo2 。掌
8、握了本教程介绍的方法和技巧,基本上可以了解实际应用中将会遇到的问题及解决办法,但本教程着眼于“简明” ,省略了一些比较不常见的问题及解决办法,如果遇到本教程未提及的问题,请参考详细教程或帮助,或者与技术支持联系。使用这示例代码进行测试,不需要 License,即演示版也可以支持。2第 1 章 安装与示例1.1 运行环境与安装1.1.1 下载与安装可从 http:/www.KaileS ,即可完成安装。1.1.2 运行环境操作系统:Windows2000, Windows XP, Windows Server 2003,Windows Vista,Windows 7。内存:128M,推荐 256
9、M。硬盘空间:200M。1.1.3 编译器目前支持的编译器包括:VC6.0、VC 2003、VC 2005、VC 2008、VC 2010、GCC 4、 G+ 4。1.1.4 适用范围适用于各类 C、+ 项目,如:使用 VC 系列开发环境开发的项目;主流嵌入式开发环境的项目,如 CodeWarrior、RealView 、Tornado 、CodeWarrior 等,Linux GCC/G+项目。1.2 示例工程介绍1.2.1 打开示例工程在“工程菜单”,点击“打开示例工程”,在弹出的子菜单中选择 IDE,即可打开示例工程。1.2.2 用于学习基本功能的示例已测试的 CMyClass 类演示了
10、 VU 的主要功能及操作,未测试的拷贝类 CMyClass2 供对照练习;已测试的 CStubDemo 类演示了底层模拟的各种应用,未测试的拷贝类 CStubDemo2 供对照练习。1.2. 3 用于体验 ETDD 的示例3EasyTDD.c 文件准备了一些不太复杂的字符串处理函数,代码未编写。可以分为两部分,一半用 ETDD 方式编写,一半用传统方式编写,以体验 ETDD 及将 ETDD 与传统编程方式进行对比。体验方法:1) 打开示例工程;2) 用您的开发环境(如 VC)打开以下文件:VU 安装目录SamplesDemoSourceC EasyTDD.c;3) 选择一个函数,在 VU 中建
11、立用例;4) 在开发 IDE 中编写函数代码,每当编译当前文件通过后,VU 都会自动执行测试并显示程序行为( 什么输入执行什么代码产生什么输出) ;5) 编写代码直到红条转换成绿条,开发和单元测试同步完成。 1.2.4 执行测试在 VU 主界面中选择要测试的函数,点击工具栏的 ,即可执行测试。1.3 快速体验 VU21) 打开示例工程,请参阅上一节。2)选中 CMyClass2:_01_Pow (),右边会自动切换到“用例代码”窗口。如左边切换到“函数代码” 窗口,则可看到预处理后的代码及功能说明。3)点击 打开输入输出生成器,填写两个参数的输入(如 g=0,e=0),和返回值的输出( 如 0
12、)。VU 会自动生成测试代码,并将数据移到表格中。4)切换到“用例数据”窗口,点击 打开用例数据生成器,为参数分别设定多个值,还可以设定各个值的组合。生成用例后,要根据程序功能设定正确的预期输出。5)点击 执行测试,然后就可以看到测试结果了。4第 2 章 建立工程2.1 示例说明下面用示例方式介绍 VU3 的使用。这里使用的示例代码,是从 VU 示例工程抽取的一些文件。为了使建立工程过程中比较常见的问题得于出现,作了一些修改:使用了编译条件_MY_DEFINE;将 cstr.c 文件的源代码移到静态库中。您可以在以下目录拷贝这些示例代码:VU 安装目录SamplesDemo2。在这里,我把示例
13、代码拷贝到 D:VUStepStepDemo2。使用这示例代码进行测试,不需要 License,即演示版也可以支持。建议按这里的介绍,一步一步进行操作练习。2.2 建立工程2.2.1 打开“ 新建工程向导”在主工具栏单击 ,或在“工程”菜单单击“新建工程” ,即可打开“新建 UDT 工程向导” 。2.2.2 模板选择先选择产品项目的开发环境,这里选择的是 Visual C+ 6,再在右边的模板列表中,根据项目特性选择合适模板,这里选择的是 C+,如下图。UDT 工程建立后,自动保存为模板,并出现在“或选择现有项目”框内,建立第二个或更多的 UDT 工程时,可选择先前的 UDT 工程作为模板,通
14、常只需设定不同的被测文件和外围文件。52.2.3 导入数据对于 VC 项目,或有 gcc/g+ makefile 文件的项目,可以这一步从工程文件导入数据,如果没有对应的工程文件,则可以跳过这一步。为了更好地描述建立过程,这里选择跳过。2.2.4 常规信息点击“浏览” ,选择产品项目根目录,这里选择的是 D:VUStepStepDemo2。填写 UDT 工程名称,该名称可以使用任务简称、模块名称或工程师姓名。这里使用缺省,如下图。62.2.5 设定测试任务如下图,按住 shift 键,点击目录前的 ,可以将文件全部展开。点击复选框,将需测试的源文件设为 T,不需测试但可能要使用的底层或关联源文
15、件设为 N,其他文件(缺省设为 X)将被隔离,必要时自动打桩。能够设为 N 的源文件不要设为 X,即尽可能减少打桩。以后可从工程菜单打开“工程属性” ,重设源文件类别或指定新加入的源文件的类别。72.2.6 指定头文件搜索目录头文件分为库头文件和常规头文件,两者的区别在于,库头文件对应的源代码位于静态或动态库中,测试时直接链接这些库,不能打桩;常规头文件对应的源代码位于普通的源文件,如果符号未实现或被隔离(例如,函数的实现被隔离) ,VU 会自动打桩。在这个示例中,头文件位于 Demo2Include目录下,该目录有三个子目录,Demo2IncludeC 和 Demo2IncludeC+目录下
16、的头文件是有对应源文件的,属于常规头文件。如下图,点击对话框中的上一个“添加” ,将这两个目录添加到常规头文件目录。Demo2IncludeLib 目录下的头文件,对应的源代码位于静态库中,点击下一个“添加” ,将Demo2IncludeLib 目录添加到库头文件目录。如果头文件目录一时难于指定,也可以暂不设定头文件目录,解析过程中,出现“找不到头文件”错误时,再打开工程属性的头文件页,使用搜索功能找出头文件目录。82.2.7 编译选项编译选项中,一般只需设置“预处理定义”一项,其他使用缺省。“预处理定义”是指会影响编译结果的编译条件,通常用于控制编译过程中忽略部分代码,可在产品项目的工程 s
17、etting 中查看。在本示例中,用 VC6 打开产品项目的工程文件:D:VUStepStepDemo2ProjectVC6C+main.dsw,打开 project setting,如下图,可以看到,除了自动添加的预处理定义外,还定义了“_MY_DEFINE” ,这就是用户设定的预处理定义,要加入到 VU 的工程属性中,使 VU 对代码的解析结果与产品项目一致。9在预处理定义框中添加“,_MY_DEFINE” ,如下图:10现在,工程的设置已经完成,回到“高级”页,点击“完成” ,VU 就会开发解析代码,解析完成后,自动打开测试 IDE,这里是打开 VC2005。下面对测试 IDE 做一些设
18、置。2.2.8 链接选项链接选项中,一般只需设置“库文件搜索目”和“链接以下库” 。如果尚不清楚需链接哪些库,可以暂不设置,待编译测试工程时,根据链接错误信息设定需添加的库。一般来说,库选项需与产品工程一致。下图是本示例的产品工程 setting 中库选项。下图是在链接选项中设置了库文件搜录目录及链接库后的界面:112.2.9 高级选项高级选项一般不需要设置。对于嵌入式项目,通常需使用“替换”功能,解决嵌入式开发环境的特殊语法造成的编译错误,但一般已在模板中预设,用户只要选择合适的模板,通常不需要进行设定,点击“完成” ,VU 开始解析代码,如果解析通过,则会生成测试文件,并自动编译。如果未找
19、到合适模板,或有其他问题,请与我们联系。1213第 3 章 常见错误与解决3.1 解析错误解析过程会自动切换到如下图口,如果产生错误,点击错误信息,即可切换到相应代码:3.1.1 解析错误:文件 xxx包含的文件xxx.h未找到常见的原因是头文件搜索目录遗漏。与一般编译器一样,VU 搜索头文件时,不搜索子目录。解决办法:点击 ,打开工程属性,切换到“头文件”页,增加 include 目录。VU 具有自动搜索头文件所在目录的功能,如果认为未找到的头文件可能是库头文件,则点击“库头文件”右侧的“搜索” 按钮,否则点击“常规头文件”右侧的“搜索”按钮,打开如下图所示的对话框:14未找到的头文件已经自
20、动列出,搜索的起始目录也已设好,如果需添加其他起始目录,请点击“添加”,不需要的起始目录,可点击选中后,再点击“删除”。点击“查找”, “查找结果”框中会列出所有包含这些头文件的目录(如果在多个目录下有同名头文件,全部列出) ,请选择正确的目录加入。头文件未找到的另一种可能原因比较少见:编译条件遗漏。编译条件是指产品项目使用了用户设定的“ 预处理定义”(可在工程 Setting 中查看,如,VC6.0 ,Preprocessor Definitions 为“WIN32,_DEBUG,_CONSOLE,_MBCS,MY_DEFINE”,则“MY_DEFINE” 就是“编译条件”) ,为了让 VU
21、 的解析结果以及测试代码的编译结果与原项目一致,UDT 工程也要使用这些“编译条件”。解决办法:切换到“编译”页,在“预处理定义”输入框中,加入编译条件。3.2 编译错误如果解析过程没有错误,解析完成后自动编译。产品代码修改后,会自动更新测试代码,并自动编译。如果修改了测试代码,可点击 或 执行测试,执行前会自动保存并视需要重新编译。编译时会自动切换到如下窗口,点击错误信息,即可跳转到对应的代码。如果需要 Rebuild All,可15点击 。3.2.1 编译错误:文件未找到可能是文件丢失,可在“代码菜单”,执行“刷新测试代码”重新生成。3.2.2 编译错误分析可以使用以下工具或方法分析错误原
22、因:1、点击错误信息,查看对应的代码,分析错误原因。2、多文件查找。在产品文件窗口,或测试文件窗口,点击 ,查找出错的关键代码。3.2.3 解决错误的途径1、工程属性的编译选项页:可以设定预处理定义,预编译头文件,强制包含文件,如果需要其他编译选项,或以直接命令行中填写,如 VC 编译器的 /MTd /MD。请注意,在命令行中添加编译选项,每个选项前要有空格。162、替换部分代码片断:可以替换代码片断来解决编译错误。打开如下窗口,按示例说明添加替换项:173、修改产品代码可以在产品代码中使用编译条件_VUNIT,在不影响产品代码的前提下作小量修改,如:产品代码为:Xxxx;修改为:#ifnde
23、f _VUNITXxxx;#elseYyyyy;#endif则只在使用 VU 测试时编译 Yyyyy;,不影响产品代码。4、直接修改测试代码测试代码可以直接修改,但在可以修改产品代码时,建议修改产品代码,因为,测试代码中,从18产品代码中拷贝的部分,在重新生成测试代码时会刷新。如下两种代码的修改比较特殊:桩代码错误:如果桩代码产生编译错误,通常可以删除桩代码,但要保留桩代码前后的标记,否则刷新时可能会自动重新生成。桩代码的标记如:/$VUNIT(BEGIN,TESTSTUB/CPersonMap:Add(PERSON*)/桩代码/$VUNIT(END,TESTSTUB/CPersonMap:A
24、dd(PERSON*)自动用例错误:如果错误位于类似于下面的代码:BVTEST_BEGIN_2(O,unsigned_B_int,g,R,0,unsigned_B_int,e,R,1)/自动用例,产生编译错误可屏蔽或删除TEST_RUN unsigned int ret = pObj-_01_Pow(g, e);/TEST_ASSERT();BVTEST_END(O,2)这是自动用例,如果涉及到未定义边界值高级类型,则可能产生编译错误,可以点击主工具栏的定义边界值,也可以将自动用例删除。3.3 链接错误链接错误主要有两种:符号未定义,符号重定义。3.3.1 符号未定义错误信息为: unreso
25、lved external symbol,或 undefined reference to、或“未定义的外部符号” 。符号未定义错误是函数或全局变量的定义不存在形成的,可能原因主要有:未链接静态库、桩代码遗漏。解决办法:分析错误信息,或利用多文件查找来分析符号的声明,弄清未定义的符号是否位于某些静态库,如果是,则在工程属性中添加静态库,如下图:19如果符号不是位于静态库,则需要补齐桩代码。方法:点击主工具栏的 ,打开桩代码管理器,如下图,用以下步骤添加桩代码:201、将出现链接错误的 obj 文件名,如 MyClass2_2.obj(VC)或 MyClass2_2.o(gcc/g+)拷贝到“文
26、件名”输入框(请注意,不要输入源文件名) 。2、将函数名全局变量的完整声明拷贝到“函数/ 变量”编辑框。如果链接错误信息中未包含完整的函数声明(例如,gcc/g+的链接错误信息中通常没有函数的返回类型) ,则要使用多文件查找,找出完整声明。3、点击“添加” 。3.3.2 符号重定义错误错误信息一般是:multiple definition of,xxx already defined in。这是存在重复定义的函数或全局变量造成的,可能的原因有:既链接了库又生成了桩;缺省链接库的顺序不对; 在头文件中定义全局变量,或在头文件中定义非 inline,非 static 全局函数;VU 生成了多余桩。
27、重定义错误信息通常示指出两个定义的位置,如:MyClass_h4_5.obj : error LNK2005: “int ABC“ (?ABC3HA) already defined in MyClass_2.obj或nafxcw.lib(afxmem.obj) : error LNK2005: “void * _cdecl operator new(unsigned 21int)“ (?2YAPAXIZ) already defined in LIBCMT.lib(new.obj)1、既链接了库又生成了桩如果一个定义位于库,一个定义位于桩代码,则属于此种情形。obj 文件名如果包含_hx_
28、(其中 x 是一个数字) ,如:abc_h4_5.obj ,则是桩代码,这是为 abc.h 中的未定义符号生成的桩文件对应的 obj 文件。解决办法:把头文件设为 L。 在“工程属性”的“头文件”页,点击常规头文件右侧的“详细分类”,打开“ 头文件分类”对话框查看) ,将该文件设为 L。如果某一目录下都是这种文件,则应该将些目录移到库头文件目录中(从常规头文件目录中删除,并在库头文件目录中添加) 。2、缺省链接库的顺序不对如果两个定义都位于库文件,则一般属于此种情形。 例如,VC6.0 报告以下链接错误:nafxcw.lib(afxmem.obj) : error LNK2005: “void
29、 * _cdecl operator new(unsigned int)“ (?2YAPAXIZ) already defined in LIBCMT.lib(new.obj)原因是 nafxcw.lib 本应在前链接,但缺省顺序不对。解决办法:显式指定链接静态库 nafxcw.lib(或 nafxcwd.lib,LIBCMT.lib 对应nafxcw.lib,LIBCMTD.lib 对应 nafxcwd.lib),这样就会首先链接 nafxcw.lib。具体方法:在工程属性-链接-链接以下库的最前面,输入要链接的库,用,分隔。如果不属于前面两种情形,则可用多文件查找,找出符号的定义,并进一步
30、分析:3、在头文件中定义全局变量,或在头文件中定义非 inline,非 static 全局函数这种情形,要修改产品文件,将定义移到源文件中,头文件添加 extern,改为声明。4、VU 生成了多余桩如果一个定义位于普通源文件,一个定义位于桩文件,则属于此种情形。解决办法:点击主工具栏的 ,打开桩代码管理器,如下图,在“搜索名称”中输入符号名,点击“搜索” ,找到后点击“屏蔽/恢复” 。如果边开发边测试,那么,有可能原来打了桩的函数,已经编写了实际代码,也会出现重定义错误,这时可以点击主工具栏的 刷新桩代码。2223第 4 章 建立用例4.1 生成用例代码左边函数列表窗口选择一个函数,这里选择的
31、是 CMyClass:Pow(),该函数未测试,右边自动切换到用例代码窗口,如下图:点击 打开输入输出生成器,填写两个参数的输入(g=0,e=0),和返回值的输出(0),如下图:24点击“确定” ,用例代码窗口就会生成用例代码,并将数据自动移到表格中。如果数据不需要移到表格中,则需移除“表格化”前的勾。只需为被测程序可能读取和改写的全局变量和成员变量设定输入输出;对于复杂数据类型,只需为被测程序可能读取和改写的域设定输入输出,忽略其他无关数据。4.2 生成用例数据切换到“用例数据”窗口,如下图,生成用例代码时设定的输入输出已经成为第一个用例。输入前面有 标记,输出前面有 标记,输入和输出之间有
32、一个空行:25点击 打开“用例生成/检查器”,根据程序功能,为各个输入设定测试数据,应考虑正常输入有哪些,边界输入有哪些,非法输入有哪些?如下图:在本例中,g 的值填了 0、1、2、5,e 的值填了 0、1、5 ,如下图:这里的数据项,是用例代码窗口通过数据表格化方式自动添加的有些数值的组合可能需要测试,点击这里设定。每个输入的取值都填写好后,再考虑不同输入取值之间的组合每个输入的取值都要考虑:有哪些正常值( 正常输入 ),有哪些边界值( 边界输入 ),有哪些非法值( 非法输入 )?数字建议自动生成。用例数据可以另存、导入,方便重用点击这里,可以根据有效范围、分段点、一些选项自动生成数据( 只支持数字 )点击这里,数据表格就会生成用例,然后再设定预期输出26还可以设定数据项的组合,如下图,只要选中的组合,VU 在生成用例时会保证覆盖到。