曾经为大家相信介绍过款常用Java测试工具代码覆盖率工具这项软件测试过程中使用的一个重要的工具却从来没介绍过来为Java?程序生成测试的覆盖率结果并提供了关于怎样分析结果以改进测试的信息本文向您展示了怎样使用IBM一款开发工具(IBM? Rational? Application Developer)中提供的代码覆盖工具如何来为Java?程序生成测试的覆盖率结果
什么是Rational Code Coverage特性?
代码覆盖率是软件测试的一个重要方面对于一个构件的总体系统测试来说可能是一个基本的参数覆盖工具背后的动机向您(作为开发员或者测试员)提供了关于代码的一系列观点这些代码在一系列的测试之中会得到检查该信息会非常的有用因为您可以使用它来设计新的测试用例以获得足够的覆盖范围
IBM? Rational? Code Coverage特性是一个与IBM? Rational? Application Developer相集成的工具您可以使用它来生成并分析关于Java程序的覆盖率统计数据工具会为测试下的程序生成声明覆盖率统计数据(这就是说执行程序中行的数量与百分比)
Rational Code Coverage特性现在只能获得Rational Application Developer 版本及其后续版本本文假设您使用的是Rational Application Developer 版本对代码覆盖率而配置IBM? WebSphere?Application Server的部分假设您使用的是版本但是提供的指南的一些调整仍然适用于上述版本
指南
为了适当地分析Rational Code Coverage特性中的覆盖率统计数据理解场景背后所用到的技术是非常重要的
Eclipse Test与Performance Tools Project(TPTP)中提供的Rational Code Coverage特性所使用的工具引擎Probekit用于控制一个类的比特代码并引入覆盖率数据收集引擎的通用访问图提供了关于这个过程的一个高层次的概述
图Rational Code Coverage执行环境的概述
基本快与可执行的单元
Probekit是一种在Eclipse平台上的框架并可以操作所谓可执行单元的比特代码可执行单元的定义与基本块的传统定义有轻微的不同但是当您在分析结果时您就需要去关注这点差异了
根据定义一个所谓的基本块就是一系列的指南这些指南不能再进行分支或者分散这里的关键思想在于当第一个指南运行的时候该块中随后所有指南都一定会得到执行而且不会得到中断接下来的是一个基本块它可以认为是一个单个组或者一系列的指南通常来说基本块的结尾是branchcallthrow或者return声明
一个可执行的单元由每一个基本快开始而与每行源代码相对应的指南与前面版本中的指南有所不同可执行的单元与基本块的不同点在于决定一个可执行单元末尾的因素例如pide指南并没有认为是一个可执行单元的结尾尽管有例外情况的存在
Probekit是Rational Code Coverage特性所使用的以将通用代码引入到每一个可执行的单元之中结果来说您可以定制Rational Code Coverage特性以向组成性(换句话说就是块覆盖率)可执行单元层次报告统计数据为了知道这些工具是怎样更改类了您可以参考接下来的代码清单与代码清单代码清单提供了未处理类的分解输出(从javap工具来)同时代码清单为处理过的类提供了分解输出注意代码清单中italics的行就是作为处理步骤一部分导入的代码部分
清单未处理的类文件
Compiled from Partjava
public class comibmstoreappmodelsPart extends javalangObject{
public comibmstoreappmodelsPart(int);
Code:
: aload_
: invokespecial #; //Method java/lang/Object<init>:()V
: iload_
: bipush
: if_icmple
: aload_
: iload_
: invokespecial #; //Method setDiscountedPrice:(I)V
: goto
: aload_
: iload_
: putfield #; //Field price:I
: return
public int getPrice();
Code:
: aload_
: getfield #; //Field price:I
: ireturn
}
清单每一个可执行单元处理的类文件
Compiled from Partjava
public class comibmstoreappmodelsPart extends javalangObject{
public comibmstoreappmodelsPart(int);
Code:
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: aload_
: invokespecial #; //Method java/lang/Object<init>:()V
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: iload_
: bipush
: if_icmple
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: aload_
: iload_
: invokespecial #; //Method setDiscountedPrice:(I)V
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: goto
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: aload_
: iload_
: putfield #; //Field price:I
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: return
public int getPrice();
Code:
: ldc #; //String com/ibm/storeapp/models/Part : iconst_ : iconst_ :
invokestatic #; //Method llc_probe$Probe__executableUnit:(Ljava/lang/String;II)V
: aload_
: getfield #; //Field price:I
: ireturn
static {}; Code: : ldc #; //String com/ibm/storeapp/models/Part : ldc #;
//String Partjava : ldc #; //String <init>(I)V+setDiscountedPrice(I)V
+getPrice()I : ldc #; //String #+ : invokestatic #;
//Method llc_probe$Probe__staticInitializer:
(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V : return
}
在Rational Application Developer中生成覆盖率统计数据
Rational Code Coverage特性的一个主要的优势在于您可以通过切换到项目Properties的Code Coverage窗格来将其在Rational Application Developer中的Java项目上激活如图所示
图项目Properties中的代码覆盖窗格
选择图中的Enable code coverage复选框以激活项目的代码覆盖率并评价覆盖下项目的类您还可以使用该窗格来定制可接受的覆盖率层次接下来描述了组合的支持层次
◆类型覆盖率一个类中覆盖的类型百分比
◆方法覆盖率一个类中覆盖的方法百分比
◆行覆盖率类文件中覆盖的行百分比
◆块覆盖率一个类文件中覆盖的块的百分比注意一个块会参考一个可执行的单元(如以前描述的那样)
您还可以指定通用的筛选规则而且它们可以用于控制在项目中评价哪些内容默认条件下项目中的所有类都会得到评价但是您可以创建通用的筛选规则来排除目标包或者指定类型如果您需要限制结果的话
Package Explorer
在您激活一个项目中的代码覆盖率以后覆盖率统计数据就会在下一次程序启动的时候生成注意不是所有类型启动配置都会自动生成统计数据表显示了Rational Application Developer内支持的启动类型
表支持的启动配置
启动类型Java AppletOSGi框架JUnitJUnit插件测试Java程序Eclipse程序标准Widget Toolkit (SWT)程序
该程序是一个不同交通工具(汽车货车摩托车等等)的简单再现图中是一个概括了该程序结构的UML图
图范例程序的UML图
在项目中有两种定义好的JUnit测试TestCarjava与TestCarImprovedjava正如其名字所暗含的一样这些测试的目标是Carjava类而在Rational Application Developer的Java视角中您可以右击TestCarjava并选择Run As > JUnit test来启动TestCarjava测试JUnit测试的结果会正常显示在JUnit视图中覆盖率数据的结果会集成到Rational Application Developer UI中而且您可以切换回Package Explorer来分析它们图显示了TestCarjava测试的一个范例结果
图Package Explorer中显示的TestCarjava的覆盖率数据
默认条件下UI只与行覆盖率信息一起注释但是您可以在工作台偏好中更改它们并且可以选择为包类型以及块而包含覆盖率每一个Java项目的百分比是最后一次执行代码覆盖率的中断您可以在Package Explorer中深入研究各种Java工件(例如类类型与方法)以得到较低组合层次上的覆盖率统计数据
结果得到的结果的颜色情况取决于成功率默认条件下红色意味着没有达到可接受的覆盖率层次而绿色则意味着得到了适当的覆盖率范围一般来说测试的目的在于达到类可接受覆盖率层次的结果
基于如图所示的结果第一个测试是不充分的Car类(以及抽象父类AbstractFourWheelVehicle和Vehicle)并不能达到适当的覆盖率层次幸运的是您有第二次尝试的机会TestCarImprovedjava您可以再一次将测试作为一次正常的JUnit执行而结果将会在Package Explorer中进行自动更新(图)
图Package Explorer中显示的TestCarImprovedjava的代码覆盖率数据
Java编辑器
行覆盖率结果也是显示的并在Java编辑器中有所标记而您可以使用它来得到一个更加明确的指示也就是每一类中涉及到了哪一行在生成覆盖率数据之后您就可以使用Java编辑器来在项目中打开任意的类了编辑器中左边的标尺栏显示了关于覆盖率的信息图显示了Vehiclejava的结果
图Java编辑器中显示的覆盖率结果
颜色编辑与在Package Explorer中所显示的是一样的也就是默认条件下绿色的行是覆盖的而红色的则不是覆盖的在Java编辑器中查看结果有一个微弱的优势那就是它还指示了部分覆盖的行当在源代码中有不止一个的可执行单元时就会产生部分覆盖的行但是它们中只有一个可以被执行例如查看图中setTargetSpeed(int speed)方法中第一行的代码第一个可执行的单元是if声明而第二个可执行的单元则是return声明默认条件下一个部分的行会被标上黄色
生成报告
您可以将代码覆盖率结果数据汇编到报告之中并在Rational Application Developer中查看它们或者将它们保存到文件系统中以便未来的分析您可以生成两种不同类型的报告Workbench报告(基于Eclipse)与HTML报告为了生成一份报告您可以选择Run>Code Coverage>Generate Report图显示了报告生成对话框
图报告生成对话框
您可以在Rational Application Developer中使用对话框中的Quick View选项来创建并查看一个报告或者使用Save Report选项将其保存到文件系统中去
工作台报告
工作台报告(也叫做基于Eclipse的报告)为项目提供了所有覆盖率统计数据的稳固视图并包含了执行时项目中所有类的覆盖率数据图显示了一个基于Eclipse流传的报告
图一个基于Eclipse报告的覆盖率结果
工作台报告与Rational Application Developer相集成具有额外的优势因为您可以使用它们作为一个快速的工具以提供了关于部分代码的视角这些代码需要改进的测试覆盖率数据如图所示工作台报告中的统计数据包含了所有层次组成的覆盖率信息从一个包到一种方法右击任意的Java工件会显示出一个带有两种操作的弹出菜单在Package Explorer中显示与在Java编辑器中将其打开对于识别和研究带有低覆盖率的代码区域来说它们是非常有用的工具因为通过将它们在适当的浏览器或者编辑器中打开从而强调了代码的选择区域
HTML报告
HTML报告显示了基于Eclipse报告所提供的相同类型的信息但是呈现的格式却是HTML的这些报告能够发挥一定程度的作用因为它们为在独立于Rational Application Developer之外去分析覆盖率数据提供了一种有效的方法您可以与团队的其他成员一起分享或者将其发布到一个网站上以方便查看
在工作台的外部生成统计数据
Rational Code Coverage工具的一个主要特性是其在Rational Application Developer外部生成统计数据的能力它提供了额外的灵活性并使得您可以定制环境以利用系统中的Rational Code Coverage特性例如一个自然的合并过程就是创建一个构建环境并使用JUnit测试来生成统计数据
通过执行以下的三个步骤评价执行以及生成报告您可以将Rational Code Coverage特性集成到您的环境之中
第步评价
您可以使用两种不同的方法来评价您的程序第一个就是使用<RAD_HOME>/plugins/comibmrationalllcengine_<date>/scripts目录中提供的instrumentbat/sh脚本本文并没有关注这个脚本但是您可以参考Rational Application Developer文献以得到更多的信息如果需要的话第二个方法是使用Rational Code Coverage特性提供的评价Ant任务代码清单显示了评价任务配置的范例用法以得到本文中的范例程序
清单本文范例程序的评价Ant任务的范例用法
<target name=instrument>
<taskdef name=instrument
classname=comibmrationalllcengineinstrumentationanttaskInstrumentationTask
classpath={path to comibmrationalllcengine plugin}/>
<instrument saveBackups=true
baseLineFile=projectbaseline
buildPath=VehicleProject
outputDir=VehicleProjectInstr/>
</target>
对预期参数的快速预览已经列在后续的表中
表指南任务的输入参数
参数描述
buildPath对文件系统上项目的路径
outputDir(可选的)评价项目的输出目录如果没有指定buildPath中的类将会进行评价
baseLineFile(可选的)基线项目索引文件的输出位置查看接下来的段落以得到关于该文件更多的信息
saveBackups(可选的)如果在评价之前先备份原始的类文件那么您可以设置为true
评价的两种方法都会输出一个基线文件所谓的基线文件是一个特定于Rational Code Coverage特性的概念基线文件包含了项目中所有类的一个索引并维护了关于每一个类的额外元数据该文件在报告阶段(接下来的第步)使用以决定程序中的哪一个类不被覆盖该步是需要的因为Rational Code Coverage数据收集引擎只是在Java? Virtual Machine(JVM)载入类时才会标记一个类所以没有执行的类的列表在没有元数据存在的条件下就不能进行决定了如果基线文件没有在报告时出现那么没有载入的类将不会出现在报告中
第步执行
为了执行评价好的类您必须在启动时对Java环境做适当的配置执行过程中所需的两个特定的参数解释如下
◆Dcoverageoutfile=<absolute path to output file>该JUM论断指定的文件就是覆盖率统计数据的输出位置
◆向classpath添加<Rational Application Developer HOME>/plugins/comibmrationalllcengine_<date>/RLCjar因为代码已经进行了评价并得到了Rational Code Coverage数据搜索引擎的回馈RLCjar文件需要在运行时位于classpath处
JUnit Ant任务提供了这些参数代码清单提供了范例用法
清单怎样指定Ant启动中Rational Code Coverage特性论断的范例
<target name=run>
<junit showoutput=true fork=yes>
<jvmarg value=Dcoverageoutfile={absolute path to the output file}/>
<classpath>
<pathelement location={absolute path to the
<Rational Application Developer HOME>/plugins/comibmrationalllcengine_<date>
/RLCjar file}/>
<pathelement location={path to the project classes}/>
<pathelement path={absolute path to the junitjar} />
</classpath>
<test name=comibmvehiclestestsTestCar outfile=TestCar />
</junit>
</target>
第步生成报告
您可以使用Rational Code Coverage特性所提供的另外一项Ant任务来生成报告该项任务使用BIRT 项目所提供的报告功能并因此需要您去下载BIRT V Reporting Engine独立版该操作可以通过访问选择V版本并下载Report Engine版本来完成注意该Ant任务只能产生HTML报告
清单提供了报告Ant任务的范例用法注意作为输入它需要在第步中所生成的覆盖率数据以及在第步中(可选)所生成的基线文件
清单本文中范例程序报告生成Ant任务的范例
<target name=generatereport>
<path id=libpath>
<pathelement location={absolute path to the
<Rational Application Developer HOME>/plugins/
common_<date>jar plugin}/>
<pathelement location={absolute path to the
<Rational Application Developer HOME>/plugins/
comibmrationalllcreport_<date> plugin}/>
<pathelement location={absolute path to the
<Rational Application Developer HOME>/plugins/
orgmon_<date>jar plugin}/>
<fileset dir={absolute path to the BIRT ReportEngine directory}\lib includes=*jar/>
</path>
<taskdef name=codecoveragereport
classname=comibmrationalllcreportbirtadaptersantReportGenerationTask
classpat/>
<codecoveragereport
outputDir={absolute path to the report output directory}
coverageDataFile={absolute path to the coveragedata file generated in step }
baseLineFiles={absolute path to the baseline file generated in step }/>
</target>
在图中显示有一个范例HTML报告使用Ant任务生成HTML报告会提供一种方法用户可以通过这种方法来查看独立于Rational Application Developer之外Ant环境中生成的统计数据
图HTML报告中的覆盖率结果
Ant环境提供了范例脚本以及构建文件该环境可以用于指导执行并生成关于范例程序的报告如果您对测试该环境感兴趣那么您可以参考一下Standalonezip文件中的README文件
在WebSphere Application Server上生成统计数据
使用WebSphere Application Server来生成代码覆盖率统计数据在这里是支持的但是不幸的是这个版本中并不支持来自Rational Application Developer内部的自动化配置但是版本中提供的Rational Code Coverage特性足够灵活以集成到服务器环境中去包括WebSphere Application Server为了对代码覆盖率而配置您的WebSphere Application Server您需要按照以下步骤进行操作
启动服务器
登录到Administrative Console
在左边的窗格中展开Servers
展开Server Types
点击WebSphere程序服务器
选择适当的程序服务器
展开右部窗格选项区域内Server Infrastructure部分中Java and Process Management项
点击Process definition
点击Additional Properties部分中的Java Virtual Machine
在 Boot Classpath部分中添加RLCjar文件如上面介绍的那样该jar文件位于Rational Code Coverage数据收集引擎中并位于<Rational Application Developer HOME>/plugins/comibmrationalllcengine_<date>/RLCjar
在Generic JVM arguments中添加Dcoverageoutfile={output file} JVM论断如上面所述的那样该论断指定了应该将输出的统计数据保存在什么地方
保存服务器配置并重启服务器
图显示了在作出以上所做的变更之后Administrative Console的屏幕截图注意在每一个服务器实例的后面必须有一个指南这些服务器实例会执行一个代码覆盖率程序
图WebSphere Application Server对Rational Code Coverage特性的配置
在服务器对代码覆盖率进行配置之后您就可以手动对服务器进行代码覆盖率的配置了(从Administration Console上进行)或者使用Rational Application Developer中的集成支持功能注意覆盖率的结果不会自动导入到Rational Application Developer中以进行分析这样您需要执行接下来的步骤来将统计数据导回到工作区中
在Rational Application Developer中的Java视角中右击Package Explorer并选择Import
展开Code Coverage
选择Code Coverage Data File并点击Next
选择Data is located on the file system选项并点击Next
在Coverage Data file区域中选择服务器所提供的文件系统上的覆盖率数据
在Into folder区域中选择工作区中的一个目录以保存导入的文件
在Associate with Project区域中选择适当的项目您应该将统计数据与工作区中的项目联系起来工作区中包含的源代码用于在服务器上生成统计数据
点击Finish
当覆盖率数据文件位于工作区中时您可以在UI中显示统计数据并生成报告您可以右击覆盖率文件并选择Code Coverage > Show code coverage indicators或者Generate Report来完成该操作该功能可以使您更加受益因为它提供了对分析Rational Application Developer中结果所用所有工具的访问途径
Paul Klicnik 是位于安大略省马克姆的 IBM 多伦多实验室的一名软件开发人员他自从 年以来从事代码覆盖工作从 年从事性能和测试工具领域的工作Paul 从事过多个 IBM 核心产品的工作包括 IBM Rational Performance Tester 和 IBM Rational Application Developer还有 Eclipse 测试和性能工具项目(TPTP)项目