软件测试是软件构建过程中非常重要的一环,测试可以完成许多事,但最重要的是可以衡量正在开发的软件的质量。有一种观点认为,在开发周期中,越早使测试成为投入的一部分越好。一个软件从代码编写开始就要面临这各种各样的测试,单元测试、集成测试、回归测试等等,其中与软件开发人员关系最紧密的就是单元测试。
单元测试的主要目的是获取应用程序中可测试软件的最小片段,将其同代码的其余部分隔离开来,然后确定它的行为是否与预期的一样。单元测试并不能保证程序是完美无缺的,但是在所有的测试中,单元测试是第一个环节,也是最重要的一个环节。单元测试的对象是软件设计中的最小单位--模块,它是一种程序员对自己的代码进行自测试的工作,其测试依据就是软件模块的详细设计文档。单元测试通常采用白盒测试的方式,白盒测试也称结构测试或逻辑驱动测试,已知产品内部工作过程,通过测试来检测内部动作是否正常。测试按照程序内部结构进行,检验程序中的每条通路是否正确工作,而不顾它的功能。测试是从代码的路径结构和内部逻辑信息设计测试用例并覆盖全部代码、分支、路径、条件。 所以,单元测试的一个很重要的指标就是代码覆盖率,很多软件开发标准化组织都对单元测试的代码覆盖率有很明确的要求,低于标准就意味着单元测试不通过。
目前有很多单元测试工具都支持程序覆盖率的自动统计,应用较广的分析覆盖率的工具有 Logiscope TestChecker、 TrueCoverage 、 PureCoverage 等,本文主要是介绍如何使用Rational公司的PureCoverage工具统计测试代码覆盖率。PureCoverage是Rational公司的单元测试工具PurifyPlus三套件之一,PurifyPlus的另外两个套件分别是内存检查工具purify和代码效率分析工具pureQuantity。本文主要介绍如何使用PureCoverage配合Microsoft的开发工具Visual C++统计单元测试的代码覆盖率。PureCoverage通过记录执行过的代码,生成代码覆盖分析报告,其代码覆盖分析可以详细到语句级,技术上的原理就是使用目标码插入OCI(Object Code Insertion)技术。所谓的目标对象插入技术,就是直接对目标码进行分析,并插入相应的汇编代码,不过源代码插入SCI(Source Code Instrumentation)和执行码替换ECI(Executable Code Interception)都需要源代码或编译环境的支持,并且会引起程序运行缓慢和系统资源占用过多的问题。但是瑕不掩瑜,PureCoverage凭借着与Visual Studio集成开发环境的无缝连接,依然是单元测试工具的首选利器。
PureCoverage有两种运行界面,一种是应用程序界面,可以脱离开发环境独立运行;另一种是嵌入式界面,可以集成到Visual Studio的集成开发环境中,不过两种运行方式的基本功能是相同的。下面用一个简单的例子作个演示,使大家对PureCoverage有一个感性的认识,这个例子就是PureCoverage自带的一个例子hello.exe。
首先运行PureCoverage,然后选择“File”菜单的“Run”命令,在弹出的“Run Program”对话框中选择hello.exe程序:
图1. 选择程序
由于hello.exe是使用Visual C++ 6.0编写的Win32应用程序,所以在“Collect Data From”选项处选择“Unmanaged Code(非托管代码)”,点击“Run”按钮就开始运行Hello.exe。PureCoverage首先分析Hello.exe装载的模块,然后润行hello.exe,出现一个标题是“Hello,World”的消息框,这是hello.exe程序的提示,要用户选择是不是看看当前的时间,我们先点击“确定”按钮看看结果。hello.exe弹出另一个消息框显示当前时间,点击“确定”按钮结束程序的运行,此时PureCoverage已经统计出了结果,如图(2)所示:
图2. 运行结果的“Module View”视图
这个视图显示了hello.c的有两个函数,DisplayLocalTime()和WinMain(),在刚才那次测试运行中被调用的次数和代码行覆盖率。用鼠标双击函数名可以将视图切换到代码窗口,如图(3)所示:
图3. 运行结果的“Source Code”视图
代码视图中被标记为蓝色的代码是刚才这次测试走过的代码,被标记为红色的代码表示这次测试没有走过的代码。如果想了解每个函数的具体情况,可以点击工具栏的“Function List”图标,图(4)就是本例中的函数列表,包括函数被调用的次数,总的代码行数,被测试过的行数以及代码覆盖率。
图4. Function List 显示
有时候一次测试通常不能覆盖所有的代码,以上面的hello.exe为例,WinMain()函数的一个分支就没有走到,PureCoverage充分考虑到了这种情况,它能够记录每一次测试结果,并提供了对结果进行分析、对比和合并的功能。下面我们再Run一下hello.exe,这次选择不看当前时间,使程序走过WinMain()函数的另一个流程。此时PureCoverage右边的“Navigator”窗口就记录下了对hello.exe的两次测试结果,如图(5)所示:
图5. 查看Navigator窗口
在Navigator窗口上用鼠标双击第二次测试的结果条目,就可以在右边看到这次测试的详细信息,如图(6)所示,这次测试Missing了DisplayLocalTime()函数,只走过了WinMain()函数的else分支。
图6. 第二次测试结果查看
此时在Navigator窗口中可以看到两个测试结果和一个自动合并结果,每测试一次PureCoverage就会自动将当前测试的结果合并到最上边的“Auto Merge”结果上。用户可以选择某几个测试结果合并成一个合并结果,比如在某种特殊条件下的几次测试就可以合并到一个结果中,以便集中统计在这种特殊条件下的测试结果。合并操作非常简单,在需要合并的测试结果上单击鼠标右键,在弹出的菜单中选择“Merge Runs”菜单,然后在弹出的结果列表中选择另一个测试结果就可以将两者合并成一个合并结果。现在用鼠标双击Navigator窗口的“Auto Merge”结果,看看两次测试的合并结果吧。图(7)显示了合并结果的,两次测试,两个函数各被调用两次,代码覆盖率都是100%。
图7. 合并结果查看
生成一个比较结果也很简单,在Navigator窗口中选择一个测试结果,单击鼠标右键,接着在弹出的菜单中选择“Compare Runs”,最后再选择另一个结果进行比较就可以了,PureCoverage会自动生成一个比较结果,用鼠标双击这个比较结果,右边就会显示详细的内容,如图(8)所示,Base是原来的结果,New是新结果:
图8. 查看结果比较
通过上面的介绍,相信大家对PureCoverage已经有了初步的了解,PureCoverage的用法非常简单,本文只是用一个简单的例子介绍了它的基本功能。俗话说“工欲善其事,必先利其器”,使用PureCoverage配合Visual Studio开发工具,能够极大的提高软件开发的质量。接下来的“PureCoverage的使用技巧”一文将以本人最近发布的开源软件--Windows系统钩子检测程序AntiHook为例,介绍一些PureCoverage的高级用法。