转帖|其它|编辑:郝浩|2010-08-20 11:16:33.000|阅读 825 次
概述:曾经为大家相信介绍过10款常用Java测试工具,代码覆盖率工具这项软件测试过程中使用的一个重要的工具却从来没介绍过,来为Java程序生成测试的覆盖率结果,并提供了关于怎样分析结果以改进测试的信息。本文向您展示了怎样使用IBM一款开发工具(IBM Rational Application Developer)中提供的代码覆盖工具如何来为Java程序生成测试的覆盖率结果。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
曾经为大家相信介绍过10款常用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 7.5版本及其后续版本。本文假设您使用的是Rational Application Developer 7.5.4版本。对代码覆盖率而配置IBM? WebSphere?Application Server的部分假设您使用的是7.0版本,但是提供的指南的一些调整仍然适用于上述版本。
指南
为了适当地分析Rational Code Coverage特性中的覆盖率统计数据,理解场景背后所用到的技术是非常重要的。
Eclipse Test与Performance Tools Project(TPTP)中提供的Rational Code Coverage特性所使用的工具引擎。Probekit用于控制一个类的比特代码,并引入覆盖率数据收集引擎的通用访问。图1提供了关于这个过程的一个高层次的概述:
图1.Rational Code Coverage执行环境的概述
基本快与可执行的单元
Probekit是一种在Eclipse平台上的框架,并可以操作所谓可执行单元的比特代码。可执行单元的定义与基本块的传统定义有轻微的不同,但是当您在分析结果时,您就需要去关注这点差异了。
根据定义,一个所谓的基本块就是一系列的指南,这些指南不能再进行分支或者分散。这里的关键思想在于,当第一个指南运行的时候,该块中随后所有指南都一定会得到执行而且不会得到中断。接下来的是一个基本块,它可以认为是一个单个组或者一系列的指南。通常来说,基本块的结尾是branch,call,throw或者return声明。
一个可执行的单元由每一个基本快开始,而与每行源代码相对应的指南与前面版本中的指南有所不同。可执行的单元与基本块的不同点,在于决定一个可执行单元末尾的因素。例如,pide指南并没有认为是一个可执行单元的结尾,尽管有例外情况的存在。
Probekit是Rational Code Coverage特性所使用的,以将通用代码引入到每一个可执行的单元之中。结果来说,您可以定制Rational Code Coverage特性以向组成性(换句话说,就是块覆盖率)可执行单元层次报告统计数据。为了知道这些工具是怎样更改类了,您可以参考接下来的代码清单1与代码清单2。代码清单1提供了未处理类的分解输出(从javap工具来),同时代码清单2为处理过的类提供了分解输出。注意代码清单2中italics的行就是作为处理步骤一部分导入的代码部分。
清单1.未处理的类文件
1.Compiled from "Part.java"
2.public class com.ibm.storeapp.models.Part extends java.lang.Object{
3.public com.ibm.storeapp.models.Part(int);
4. Code:
5. 0: aload_0
6. 1: invokespecial #15; //Method java/lang/Object."<init>":()V
7. 4: iload_1
8. 5: bipush 10
9. 7: if_icmple 18
10. 10: aload_0
11. 11: iload_1
12. 12: invokespecial #18; //Method setDiscountedPrice:(I)V
13. 15: goto 23
14. 18: aload_0
15. 19: iload_1
16. 20: putfield #21; //Field price:I
17. 23: return
18.
19. public int getPrice();
20. Code:
21. 0: aload_0
22. 1: getfield #21; //Field price:I
23. 4: ireturn
24.
25.}
清单2.每一个可执行单元处理的类文件
26.Compiled from "Part.java"
27.public class com.ibm.storeapp.models.Part extends java.lang.Object{
28.public com.ibm.storeapp.models.Part(int);
29. Code:
30. 0: ldc #49; //String com/ibm/storeapp/models/Part 2: iconst_0 3: iconst_0 4:
31. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
32. 7: aload_0
33. 8: invokespecial #15; //Method java/lang/Object."<init>":()V
34. 11: ldc #49; //String com/ibm/storeapp/models/Part 13: iconst_0 14: iconst_1 15:
35. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
36. 18: iload_1
37. 19: bipush 10
38. 21: if_icmple 46
39. 24: ldc #49; //String com/ibm/storeapp/models/Part 26: iconst_0 27: iconst_2 28:
40. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
41. 31: aload_0
42. 32: iload_1
43. 33: invokespecial #18; //Method setDiscountedPrice:(I)V
44. 36: ldc #49; //String com/ibm/storeapp/models/Part 38: iconst_0 39: iconst_3 40:
45. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
46. 43: goto 58
47. 46: ldc #49; //String com/ibm/storeapp/models/Part 48: iconst_0 49: iconst_4 50:
48. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
49. 53: aload_0
50. 54: iload_1
51. 55: putfield #21; //Field price:I
52. 58: ldc #49; //String com/ibm/storeapp/models/Part 60: iconst_0 61: iconst_5 62:
53. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
54. 65: return
55.
56. public int getPrice();
57. Code:
58. 0: ldc #49; //String com/ibm/storeapp/models/Part 2: iconst_2 3: iconst_0 4:
59. invokestatic #48; //Method llc_probe$Probe_0._executableUnit:(Ljava/lang/String;II)V
60. 7: aload_0
61. 8: getfield #21; //Field price:I
62. 11: ireturn
63.static {}; Code: 0: ldc #49; //String com/ibm/storeapp/models/Part 2: ldc #55;
64. //String Part.java 4: ldc #57; //String <init>(I)V+setDiscountedPrice(I)V
65. +getPrice()I 6: ldc #59; //String #10+11032,301,3 8: invokestatic #54;
66. //Method llc_probe$Probe_0._staticInitializer:
67. (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V 11: return
68.
69.}
在Rational Application Developer中生成覆盖率统计数据
Rational Code Coverage特性的一个主要的优势在于,您可以通过切换到项目Properties的Code Coverage窗格,来将其在Rational Application Developer中的Java项目上激活,如图2所示。
图2.项目Properties中的代码覆盖窗格
选择图2中的Enable code coverage复选框以激活项目的代码覆盖率,并评价覆盖下项目的类。您还可以使用该窗格来定制可接受的覆盖率层次。接下来描述了组合的支持层次:
◆类型覆盖率:一个类中覆盖的类型百分比
◆方法覆盖率:一个类中覆盖的方法百分比
◆行覆盖率:类文件中覆盖的行百分比
◆块覆盖率:一个类文件中覆盖的块的百分比。注意一个块会参考一个可执行的单元(如以前描述的那样)
您还可以指定通用的筛选规则,而且它们可以用于控制在项目中评价哪些内容。默认条件下,项目中的所有类都会得到评价,但是您可以创建通用的筛选规则来排除目标包或者指定类型,如果您需要限制结果的话。
Package Explorer
在您激活一个项目中的代码覆盖率以后,覆盖率统计数据就会在下一次程序启动的时候生成。注意不是所有类型启动配置都会自动生成统计数据。表1显示了Rational Application Developer内支持的启动类型。
表1.支持的启动配置
启动类型 |
Java Applet |
OSGi框架 |
JUnit |
JUnit插件测试 |
Java程序 |
Eclipse程序 |
标准Widget Toolkit (SWT)程序 |
该程序是一个不同交通工具(汽车、货车、摩托车等等)的简单再现。图3中是一个概括了该程序结构的UML图。
图3.范例程序的UML图
在项目中有两种定义好的JUnit测试:TestCar.java与TestCarImproved.java。正如其名字所暗含的一样,这些测试的目标是Car.java类。而在Rational Application Developer的Java视角中,您可以右击TestCar.java并选择Run As > JUnit test来启动TestCar.java测试。JUnit测试的结果会正常显示在JUnit视图中。覆盖率数据的结果会集成到Rational Application Developer UI中,而且您可以切换回Package Explorer来分析它们。图4显示了TestCar.java测试的一个范例结果。
图4.Package Explorer中显示的TestCar.java的覆盖率数据
默认条件下,UI只与行覆盖率信息一起注释;但是,您可以在工作台偏好中更改它们,并且可以选择为包、类型以及块而包含覆盖率。每一个Java项目的百分比是最后一次执行代码覆盖率的中断。您可以在Package Explorer中深入研究各种Java工件(例如,类、类型与方法)以得到较低组合层次上的覆盖率统计数据。
结果得到的结果的颜色情况取决于成功率:默认条件下,红色意味着没有达到可接受的覆盖率层次,而绿色则意味着得到了适当的覆盖率范围。一般来说,测试的目的在于达到类可接受覆盖率层次的结果。
基于如图4所示的结果,第一个测试是不充分的:Car类(以及抽象父类AbstractFourWheelVehicle和Vehicle)并不能达到适当的覆盖率层次。幸运的是,您有第二次尝试的机会:TestCarImproved.java。您可以再一次将测试作为一次正常的JUnit执行,而结果将会在Package Explorer中进行自动更新(图5)。
图5.Package Explorer中显示的TestCarImproved.java的代码覆盖率数据
Java编辑器
行覆盖率结果也是显示的,并在Java编辑器中有所标记,而您可以使用它来得到一个更加明确的指示,也就是每一类中涉及到了哪一行。在生成覆盖率数据之后,您就可以使用Java编辑器来在项目中打开任意的类了,编辑器中左边的标尺栏显示了关于覆盖率的信息。图6显示了Vehicle.java的结果:
图6.Java编辑器中显示的覆盖率结果
颜色编辑与在Package Explorer中所显示的是一样的。也就是,默认条件下,绿色的行是覆盖的而红色的则不是覆盖的。在Java编辑器中查看结果有一个微弱的优势,那就是它还指示了部分覆盖的行。当在源代码中有不止一个的可执行单元时就会产生部分覆盖的行,但是它们中只有一个可以被执行。例如,查看图6中setTargetSpeed(int speed)方法中第一行的代码:第一个可执行的单元是if声明,而第二个可执行的单元则是return声明。默认条件下,一个部分的行会被标上黄色。
生成报告
您可以将代码覆盖率结果数据汇编到报告之中并在Rational Application Developer中查看它们,或者将它们保存到文件系统中以便未来的分析。您可以生成两种不同类型的报告:Workbench报告(基于Eclipse)与HTML报告。为了生成一份报告,您可以选择Run>Code Coverage>Generate Report。图7显示了报告生成对话框。
图7.报告生成对话框
您可以在Rational Application Developer中使用对话框中的Quick View选项来创建并查看一个报告,或者使用Save Report选项将其保存到文件系统中去。
工作台报告
工作台报告(也叫做基于Eclipse的报告)为项目提供了所有覆盖率统计数据的稳固视图,并包含了执行时项目中所有类的覆盖率数据。图8显示了一个基于Eclipse流传的报告。
图8.一个基于Eclipse报告的覆盖率结果
工作台报告与Rational Application Developer相集成具有额外的优势,因为您可以使用它们作为一个快速的工具,以提供了关于部分代码的视角,这些代码需要改进的测试覆盖率数据。如图8所示,工作台报告中的统计数据包含了所有层次组成的覆盖率信息:从一个包到一种方法。右击任意的Java工件会显示出一个带有两种操作的弹出菜单:在Package Explorer中显示与在Java编辑器中将其打开。对于识别和研究带有低覆盖率的代码区域来说,它们是非常有用的工具,因为通过将它们在适当的浏览器或者编辑器中打开,从而强调了代码的选择区域。
HTML报告
HTML报告显示了基于Eclipse报告所提供的相同类型的信息,但是呈现的格式却是HTML的。这些报告能够发挥一定程度的作用,因为它们为在独立于Rational Application Developer之外去分析覆盖率数据提供了一种有效的方法,您可以与团队的其他成员一起分享,或者将其发布到一个网站上以方便查看。
在工作台的外部生成统计数据
Rational Code Coverage工具的一个主要特性是其在Rational Application Developer外部生成统计数据的能力。它提供了额外的灵活性,并使得您可以定制环境以利用系统中的Rational Code Coverage特性。例如,一个自然的合并过程就是创建一个构建环境并使用JUnit测试来生成统计数据。
通过执行以下的三个步骤:评价,执行以及生成报告,您可以将Rational Code Coverage特性集成到您的环境之中。
第1步.评价
您可以使用两种不同的方法来评价您的程序。第一个就是使用<RAD_HOME>/plugins/com.ibm.rational.llc.engine_<date>/scripts目录中提供的instrument.bat/sh脚本。本文并没有关注这个脚本,但是您可以参考Rational Application Developer文献以得到更多的信息,如果需要的话。第二个方法是使用Rational Code Coverage特性提供的评价Ant任务。代码清单3显示了评价任务配置的范例用法,以得到本文中的范例程序。
清单3.本文范例程序的评价Ant任务的范例用法
1.<target name="instrument">
2. <taskdef name="instrument"
3. classname="com.ibm.rational.llc.engine.instrumentation.anttask.InstrumentationTask"
4. classpath="{path to com.ibm.rational.llc.engine plugin}"/>
5. <instrument saveBackups="true"
6. baseLineFile="project.baseline"
7. buildPath="VehicleProject"
8. outputDir="VehicleProjectInstr"/>
9.</target>
对预期参数的快速预览,已经列在后续的表2中。
表2.指南任务的输入参数
参数描述
buildPath对文件系统上项目的路径
outputDir(可选的)评价项目的输出目录。如果没有指定,buildPath中的类将会进行评价。
baseLineFile(可选的)基线项目索引文件的输出位置。查看接下来的段落以得到关于该文件更多的信息。
saveBackups(可选的)如果在评价之前先备份原始的类文件,那么您可以设置为true。
评价的两种方法都会输出一个基线文件。所谓的基线文件是一个特定于Rational Code Coverage特性的概念。基线文件包含了项目中所有类的一个索引,并维护了关于每一个类的额外元数据。该文件在报告阶段(接下来的第3步)使用以决定程序中的哪一个类不被覆盖。该步是需要的,因为Rational Code Coverage数据收集引擎只是在Java? Virtual Machine(JVM)载入类时才会标记一个类,所以没有执行的类的列表在没有元数据存在的条件下就不能进行决定了。如果基线文件没有在报告时出现,那么没有载入的类将不会出现在报告中。
第2步.执行
为了执行评价好的类,您必须在启动时对Java环境做适当的配置。执行过程中所需的两个特定的参数解释如下:
◆-Dcoverage.out.file=<absolute path to output file>:该JUM论断指定的文件就是覆盖率统计数据的输出位置
◆向classpath添加<Rational Application Developer HOME>/plugins/com.ibm.rational.llc.engine_<date>/RLC.jar:因为代码已经进行了评价并得到了Rational Code Coverage数据搜索引擎的回馈,RLC.jar文件需要在运行时位于classpath处。
JUnit Ant任务提供了这些参数。代码清单4提供了范例用法。
清单4.怎样指定Ant启动中Rational Code Coverage特性论断的范例
10.<target name="run">
11. <junit showoutput="true" fork="yes">
12. <jvmarg value="-Dcoverage.out.file={absolute path to the output file}"/>
13. <classpath>
14. <pathelement location="{absolute path to the
15. <Rational Application Developer HOME>/plugins/com.ibm.rational.llc.engine_<date>
16. /RLC.jar file}"/>
17. <pathelement location="{path to the project classes}"/>
18. <pathelement path="{absolute path to the junit.jar}" />
19. </classpath>
20. <test name="com.ibm.vehicles.tests.TestCar" outfile="TestCar" />
21. </junit>
22.</target>
第3步.生成报告
您可以使用Rational Code Coverage特性所提供的另外一项Ant任务来生成报告。该项任务使用BIRT Eclipse.org项目所提供的报告功能。清单5提供了报告Ant任务的范例用法。注意,作为输入,它需要在第2步中所生成的覆盖率数据以及在第1步中(可选)所生成的基线文件。
清单5.本文中范例程序报告生成Ant任务的范例
1.<target name="generate-report">
2. <path id="lib.path">
3. <pathelement location="{absolute path to the
4. <Rational Application Developer HOME>/plugins/
5. com.ibm.rational.llc.common_<date>.jar plugin}"/>
6. <pathelement location="{absolute path to the
7. <Rational Application Developer HOME>/plugins/
8. com.ibm.rational.llc.report_<date> plugin}"/>
9. <pathelement location="{absolute path to the
10. <Rational Application Developer HOME>/plugins/
11. org.eclipse.equinox.common_<date>.jar plugin}"/>
12. <fileset dir="{absolute path to the BIRT ReportEngine directory}\lib" includes="*.jar"/>
13. </path>
14.
15. <taskdef name="code-coverage-report"
16. classname="com.ibm.rational.llc.report.birt.adapters.ant.ReportGenerationTask"
17. classpathref="lib.path"/>
18.
19. <code-coverage-report
20. outputDir="{absolute path to the report output directory}"
21. coverageDataFile="{absolute path to the coveragedata file generated in step 1}"
22. baseLineFiles="{absolute path to the baseline file generated in step 1}"/>
23.</target>
在图9中显示有一个范例HTML报告。使用Ant任务生成HTML报告会提供一种方法,用户可以通过这种方法来查看独立于Rational Application Developer之外Ant环境中生成的统计数据。
图9.HTML报告中的覆盖率结果
Ant环境提供了范例脚本以及构建文件,该环境可以用于指导、执行并生成关于范例程序的报告。如果您对测试该环境感兴趣,那么您可以参考一下Standalone.zip文件中的README文件。
在WebSphere Application Server上生成统计数据
使用WebSphere Application Server来生成代码覆盖率统计数据在这里是支持的,但是不幸的是,这个版本中并不支持来自Rational Application Developer内部的自动化配置。但是,版本中提供的Rational Code Coverage特性足够灵活以集成到服务器环境中去,包括WebSphere Application Server。为了对代码覆盖率而配置您的WebSphere Application Server,您需要按照以下步骤进行操作:
1.启动服务器
2.登录到Administrative Console
3.在左边的窗格中,展开Servers
4.展开Server Types
5.点击WebSphere程序服务器
6.选择适当的程序服务器
7.展开右部窗格选项区域内Server Infrastructure部分中Java and Process Management项
8.点击Process definition
9.点击Additional Properties部分中的Java Virtual Machine
10.在 Boot Classpath部分中,添加RLC.jar文件。如上面介绍的那样,该.jar文件位于Rational Code Coverage数据收集引擎中,并位于<Rational Application Developer HOME>/plugins/com.ibm.rational.llc.engine_<date>/RLC.jar
11.在Generic JVM arguments中,添加-Dcoverage.out.file={output file} JVM论断。如上面所述的那样,该论断指定了应该将输出的统计数据保存在什么地方。
12.保存服务器配置并重启服务器。
图10显示了在作出以上所做的变更之后Administrative Console的屏幕截图。注意在每一个服务器实例的后面必须有一个指南,这些服务器实例会执行一个代码覆盖率程序。
图10.WebSphere Application Server对Rational Code Coverage特性的配置
在服务器对代码覆盖率进行配置之后,您就可以手动对服务器进行代码覆盖率的配置了(从Administration Console上进行),或者使用Rational Application Developer中的集成支持功能。注意覆盖率的结果不会自动导入到Rational Application Developer中以进行分析,这样您需要执行接下来的步骤来将统计数据导回到工作区中:
1.在Rational Application Developer中的Java视角中,右击Package Explorer并选择Import
2.展开Code Coverage
3.选择Code Coverage Data File并点击Next
4.选择Data is located on the file system选项并点击Next
5.在Coverage Data file区域中,选择服务器所提供的文件系统上的覆盖率数据
6.在Into folder区域中,选择工作区中的一个目录以保存导入的文件。
7.在Associate with Project区域中选择适当的项目。您应该将统计数据与工作区中的项目联系起来,工作区中包含的源代码用于在服务器上生成统计数据。
8.点击Finish
当覆盖率数据文件位于工作区中时,您可以在UI中显示统计数据并生成报告。您可以右击覆盖率文件并选择Code Coverage > Show code coverage indicators或者Generate Report来完成该操作。该功能可以使您更加受益,因为它提供了对分析Rational Application Developer中结果所用所有工具的访问途径。
Paul Klicnik 是位于安大略省马克姆的 IBM 多伦多实验室的一名软件开发人员。他自从 2008 年以来从事代码覆盖工作,从 2006 年从事性能和测试工具领域的工作。Paul 从事过多个 IBM 核心产品的工作,包括 IBM Rational Performance Tester 和 IBM Rational Application Developer,还有 Eclipse 测试和性能工具项目(TPTP)项目。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
文章转载自:网络转载