??xml version="1.0" encoding="utf-8" standalone="yes"?>77777影视视频在线观看,日韩中文字幕第一页,自拍亚洲图区http://www.aygfsteel.com/supsky/zh-cnWed, 18 Jun 2025 17:22:48 GMTWed, 18 Jun 2025 17:22:48 GMT60ClearCase指南-基础(朋伟)http://www.aygfsteel.com/supsky/archive/2006/08/10/62749.htmleddy liaoeddy liaoThu, 10 Aug 2006 03:18:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/08/10/62749.htmlhttp://www.aygfsteel.com/supsky/comments/62749.htmlhttp://www.aygfsteel.com/supsky/archive/2006/08/10/62749.html#Feedback1http://www.aygfsteel.com/supsky/comments/commentRss/62749.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/62749.htmlhttp://www.javaresource.org/clearcase/clearcase-73883.html

我这都是转的一些东?img src ="http://www.aygfsteel.com/supsky/aggbug/62749.html" width = "1" height = "1" />

eddy liao 2006-08-10 11:18 发表评论
]]>
Base ClearCase与ClearQuest的集??http://www.aygfsteel.com/supsky/archive/2006/08/09/62608.htmleddy liaoeddy liaoWed, 09 Aug 2006 09:04:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/08/09/62608.htmlhttp://www.aygfsteel.com/supsky/comments/62608.htmlhttp://www.aygfsteel.com/supsky/archive/2006/08/09/62608.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/62608.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/62608.htmlhttp://www.chinaitpower.com/2005September/2005-09-13/205598.html

Rational ClearCase是一个业界领先的软g配置理工具QRational ClearQuest则是IBM Rational在变更管理和~陷跟踪斚w的Y件。业界对于变更管理Y件和配置理软g的集成有着强烈的需求,因此IBM Rational也提供了ClearCase和ClearQuest集成的功?

1 概述

Rational ClearCase是一个业界领先的软g配置理工具QRational ClearQuest则是IBM Rational在变更管理和~陷跟踪斚w的Y件。业界对于变更管理Y件和配置理软g的集成有着强烈的需求,因此IBM Rational也提供了ClearCase和ClearQuest集成的功能?/p>

所谓Base ClearCase和ClearQuest的集成,是ClearQuest中的变更h(Change Requeset)兌C个或多个ClearCase中元?Element)的版?Version)上。一个变更请求可以被兌C个或多个版本上,实施变更的这些版本的集合被称作变更请求的变更?Change Set)。一个版本可以被兌C个或多个变更hQ这些变更请求的集合被称作版本的h?Request Set)?/p>

集成对于不同的角Ԍ有以下不同的功能Q?/p>

一个项目经理指定在什么情况下需要让用户兌版本到变更请求。也可以指定兌变更h的VOBsQbranchesQ以及element types?/p>

ClearQuest的管理员dClearCase的定义到ClearQuest的schema中。这使得变更h可以昄与它兌的变更集?/p>

使用ClearCaseq行开发的人员Q可以在Check Out或者Check In一个版本的时候,这个版本关联到一个或者更多的变更h上。也可以查看一个变更请求的变更集?/p>

在这文章中Q我们将对Base ClearCase与ClearQuest集成的设计原理和q行环境的搭Z讄q行介绍Q最后再提供一些操作范例?br />

2 基本概念

2.1 集中方式(Central Server)

所谓的Central Server是所有的脚本文g及配|文件放在一个目录,当进行集成的时候,ClearCase׃在这个目录中L配置文gQconfig.plQ、cqcc_launch脚本以及其他的代码,而不是用本地默认目录的相应文gQ因此提高了安全性和可维护性。与之对应的本地方式(Local Server)则是使用本地ClearCase目录中的配置文g、脚本以及其他代码?/p>

2.2 批处?Batching Enabled)

是一个ClearCase操作中的所有与ClearQuest相关的操作,记录C个批处理文g中,ClearCase操作完成之后Q再这些操作一ơ性写入到ClearQuest中。从而降低了登陆ClearQuest和在查询ClearQuest的次敎ͼ大大的提高了性能?/p>

2.3 序列(Batching Series)

批处理序列是批处理的概念进一步扩展的产物。ClearCase认ؓ所有进行的ClearCase都是在一个批处理当中Q它记录所有与ClearQuest相关的操作到批处理文件当中,以便在以后的某个旉完成与ClearQuest相关的操作?/p>

2.4 入后提交(Postcheckin commit)

是在ClearCase的Check in完成之后Q再q行ClearQuest的操作。一般的情况下,在ClearCase的Check in操作完成之后Q才q行与ClearQuest相关的操作。这样在Check in操作p|的情况下Q会造成ClearCase和ClearQuest的数据不一致。启用此功能则可以避免这U错误?/p>

2.5 自动兌(Auto-association)

是在将变更h兌到某个版本的时候,不需要手工选择Q而是靠预先设|的hID或者根据ClearCase操作的注释自动提取请求IDQ来军_兌的请求?/p>

2.6 使用CQWeb方式的集?/p>

在本地没有安装ClearQuestQ或者不愿意使用本地的ClearQuest的情况下Q可以用CQWeb的方式用CQWeb Server上的ClearQuest来实现ClearCase和ClearQuest的集成?br />

3 何时采用Base ClearCase

我们知道UCM是一U对版本控制的配制管理流E,而UCM是基于Base ClearCase的管理流E演变而来的。因此掌握ƈ了解Base ClearCase的管理就昑־臛_重要。Base ClearCase包含了一pd功能Q它们能够开发h员做到ƈ行开发,目理者也能通过制定相关的规则来使开发工作有序的q行?/p>

在开发过E中QBase ClearCase应用"分支(Branch)"的方法来允许开发h员进行ƈ行开发。Q何在配制理下的元素(Element)Q例如:文本文gQ程序原代码{,都会生成一个主分支Q而主分支下还可以有多个下属分支,它们的作用是用来支持在主分支上的开发。Base ClearCase 允许创徏复杂的分支体pR在开发过E中Q通过视图QViewQ可以访问特定元素集的特定版本,而这通过修改视图的规?Config Specification)可以实现。UCM也?分支"的方法,但是q些分支不需要用手工来操作,而是通过"?Stream)"来实玎ͼ通常情况下,一个项目存在一个集成流和多个开发流?/p>

在项目管理方面,我们通过寚w目的源文件打基线(Baseline)来呈现项目早期较E_版本的雏形,q且基线可以用来q接一pd相关的源文gQ比如像源代码,试计划{等。UCM自动完成基线的创建,而Base ClearCase则通过对元?Elements)的版本打标签来创建基Uѝ?/p>

通过以上对UCM和Base ClearCase的比较,因此在一个项目不是很大,q且业务程相对单的情况下适合用Base ClearCase?br />

4 q行环境的搭Z讄

4.1 q行环境的搭?/font>

在Base CCCQ集成的过E中Q运行环境的搭徏ؓ重要?/p>


?(01) pȝl构?/b>

首先Q需要在ClearCase客户端和ClearCase注册服务器安装ClearCase。在ClearQuest Unix服务器和ClearQuest Windows服务器安装ClearQuest。准备数据库服务器。在ClearQuest Unix服务器上配置好DBSetQƈdUser DB。之后就可以配置集成了?/p>

4.2 ClearCase与ClearQuest集成的配?/font>

集成的配|需要在ClearCase和ClearQuest上分别进行配|,才能完成。在ClearCase侧,需要对VOB配置。当对一个VOB配置了集成之后,针对与这个VOB的ClearCase相关操作Q例如CheckOut, CheckInQ都会激发脚本对ClearQuest数据库的讉KQ进而完成Base CC和CQ的集成?/p>

在ClearQuest侧,需要在数据库中dClearCase的定义,只有加入了定义之后,数据库中的请求的变更集才能够昄出来?/p>

下面具体介绍配置q程?/p>

4.2.1 ClearCase package加入C个ClearQuest DBset

׃ClearQuest schema包含了一些与多个ClearQuest user databases相关联的Ҏ,例如数据记录的类型,区域Q和形式。在开发h员将ClearCase中文件的版本与ClearQuest用户数据库中的变更请求相联系的时候,必须ClearCase的特性也加入到ClearQuest schemaQ此q程要在Windows端完成且q程如下所qͼ

  • 开?-> E序 -> Rational Software -> Rational ClearQuest -> ClearQuest Designer
  • 在ClearQuest Designer中,点击Package -> Package Wizard
  • 在安装Package向导中,扑ֈClearCase 1.0和ClearCase Upgrade 1.0Q如果这些Packages没有列出Q则点击"More Packages"Qƈ上q的两个Packagesd到列表中?
  • 选择ClearCase 1.0 Packageq点?下一?
  • 选择一个将会应用ClearCase 1.0 Package的schema e.g. Defect TrackingQ点?下一?
  • 选择数据U录的类型ƈ点击"完成"
  • 选择File -> Check In来保存schema的最新版?
  • 选择Database -> Upgrade Database把schema的最新版本升U到ClearQuest user database?/li>

4.2.2 在ClearCase VOBs上安装触发器(Triggers)

CCCQ的集成应用到了针对cleartool checkin, checkout和uncheckout操作的触发器Q触发器的安装与配制需要在Windows端配Ӟ该Windows的Registry Server必须与UNIX上徏VOBs的那台Server指向同一台Registry Server。具体配|过E如下所qͼ

4.2.2.1 同步UNIX与Windows上的ClearCase Regions

1) 在Windows上新Z个RegionQ名UC需要同步的UNIX上的Region名称相同Q这时UNIX上的Region在Registry Server上注册了?/p>

2) q行 -> cleartool -> mkregion -tag <UNIX region>

3) 开?-> E序 -> Rational Software ->

4) Rational ClearCase'Administration'Region Synchronizer


?(02) 导入Unix服务器上的VOB

5) 选择需要同步的Windows Region和UNIX Region, 在Import Type一上选择"VOB Tags"q且选中"Show full storage directory paths.

6) ?Unix VOB tags not found in the Windows region"列表中选择需要引入的VOBQ点?Import"Q这?Create VOB Tag"对话框会昄出来。在"Global Storage"一中输入在UNIX服务器上的VOB的网l存储\径,q且?Hostname"一中输入在Region内能够解析的L名?/p>


?(03) 创徏Tag

4.2.2.2 一个VOB安装上Trigger

当一个VOB被引入(ImportQ后Q我们可以对其安装Trigger 在ClearCase中,点击开?-> E序 -> Rational Software'Rational ClearCase'Administration'Integrations'ClearQuest Integration Configuration. q时出现如下图所C的对话框?/p>


?(04) 应用Trigger

?ClearCase - ClearQuest Integration Configuration"对话框中Q我们可以看到所有在UNIX服务器端建立好的VOBsQƈ且可以对其中M一个VOB安装trigger。在q里Q我们对VOB int4安装Checkout和Checkin的trigger。Trigger的配制文件在config.pl中有详细说明Q关于trigger选择的详l内容可以参看上一章节?/p>

提示Q?/p>

  • 触发器用config.pl配制文g来控制本地集成的配制参数。当选择V2触发器时Q配|应用程序会config.pl文g路径设ؓCQCC/config.plQ在q个路径中CQCC代表了本地的cc-home-dir/lib/perl5/CQCCTrigger/CQCCq个路径Q用户可以根据需要将q个路径改变Z个UNC路径Q因此所有的集成操作调用一个中心配制文件config.pl?
  • 在安装触发器Ӟ只有VOB的所有者才可以对自己创建的VOB安装触发器。如果一个用户e.g. Harry登陆WindowsQ他惛_Andy在UNIX上创建的VOB安装触发器,q时会出?无法得到触发器类?{警告。如果Harry希望可以对VOB安装触发器,那么需要执行以下两步:
  • 在DOS模式下运行Runas /user:RATIONALCC\Andy cmd.exe命oQ这个命令将以Andy的n份打开一个DOSH口Qƈ提示输入用户名和密码?
  • 在验证通过登陆后,另一个DOSH口会打开Q在q个H口中,q行"cqconfig"来以Andy的n份在VOB上安装触发器?/li>

4.2.3 核心文gconfig.pl的配|?/b>

config.pl文g的配|在Base ClearCase与ClearQuest集成的操作中起到重要的作用。config.pl文g中包含了一pd变量及参数的讄Q设|的描述Q以及在哪里可以配制q些参数Q是在config.pl文g本n中设|还是在pȝ环境变量中设|)?

config.pl文g在不同操作系l上的存储\径:
Windows:C:\Program Files\Rational\Clearcase\lib\perl5\CQCCTrigger\CQCC\config.pl
UNIX: /usr/atria/sun5/lib/perl/CQCCTrigger/CQCC/config.pl

下面׃些重要的参数配置q行详细的说明:

4.2.3.1 定义用户数据?/p>

&SetConfigParm("CQCC_DATABASE_ENTITY_LIST","SAMPL: defect");
CQCC_DATABASE_ENTITY_LIST参数定义了一个或多个数据库和数据库所支持的数据纪录类型。当定义多个数据库时Q参数的使用格式为:dbname1: entity1,entity2; dbname2: entity3,entity4。值得注意的是数据U录cd必须为在schema中已定义好的内容?/p>

4.2.3.2 定义DBsets

&SetConfigParm("CQCC_DATABASE_SET", "<db_set_name>");
在ClearQuest中,当徏立有多个DBsetsӞx多个schema存储I间ӞCQCC_DATABASE_SET参数用来指定一个当前可以用的schema存储I间?/p>

4.2.3.3 选择集成模式: 文本模式或图形模?/p>

&SetConfigParm("CQCC_GUI_ENABLE", "OFF");
此参数是一个开启Perl/TK GUI囑Ş界面的开兟뀂如果设|ؓ"ON"Q默认情况下Q,那么囑Ş界面会在需要的情况下显C,例如Q在q行xclearcase时。如果设|ؓ"Always"Q那么图形界面会在命令行操作的Ş式也昄。如果设|ؓ"OFF"Q那么图形界面将永远不显C,因此只可以用命o行操作?/p>

4.2.3.4 开启DEBUG模式

&SetConfigParm("CQCC_DEBUG", "1");

此参数用来控制在q行时模式下DEBUG报告的输出别? - 代表没有输出Q? - 代表基本输出Q针寚wU别的操作)Q? - 代表l节输出?/p>

提示Q其他参数设|的详细说明请参看config.pl文g?/p>

4.2.4 执行Base CCCQ集成的最后检?/b>

此时Q根据以上所提供的信息,我们应能够完成cqcc验,验ClearCase与ClearQuest是否能够很有效的l合Qƈ可以开始完成一些简单的操作?/p>

在UNIX客户端运行:cqcc_launch -test

此时Qcqcc_launch命o会调用config.pl里的参数q试图连接ClearQuestQ如果连接成功,exit_status会显C?Q否则将昄1Q如下图所C)


?(05) 验证配置


5 在Windows的^C的操作范?/font>

可以_Base ClearCase的基本操作,是Check Out和Check in两个操作Q下面就单介l一下这两个操作?/p>

5.1 Check Out

1) 在ClearCase Explorer中,选中一个文Ӟq行Check Out操作。如果是配置完成后第一ơ进行操作,需要输入ClearQuest的用户名和密码?/p>


?(06) 登陆H口

2) 登陆成功后,׃出现QSW(Query Association Window)H口Q显C满x件的~陷。选择~陷Q点击Association按钮Q可以将其放C侧窗口中Q点击OKQ即可完成关联?/p>


?(07) 兌H口

3) 兌成功后,在ClearQuest中打开相应的缺P在ClearCase中Q可以查看到兌的文件?/p>


?(08) 在ClearQuest中查询关联的文g

4) 在ClearCase Explorer中右键点击被兌的文Ӟ选择版本属性,查看被关联的~陷?/p>


?(09) 在ClearCase中查询关联的问题

5.2 Check In

1) 在ClearCase Explorer中选中文gQ进行Check Out操作Q弹出QSWH口?/p>


?(10) 兌H口

2) 在ClearQuest中查看被兌的文件?/p>


?(11) 在ClearQuest中查询关联的文g

3) 在ClearCase中查看被兌的缺陗?/p>


?(12) 在ClearCase中查询关联的文g



eddy liao 2006-08-09 17:04 发表评论
]]>
ClearCase articlehttp://www.aygfsteel.com/supsky/archive/2006/07/25/59988.htmleddy liaoeddy liaoTue, 25 Jul 2006 06:01:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/07/25/59988.htmlhttp://www.aygfsteel.com/supsky/comments/59988.htmlhttp://www.aygfsteel.com/supsky/archive/2006/07/25/59988.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/59988.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/59988.html1.在不同网l环境中ClearCase的管?br />http://www-128.ibm.com/developerworks/cn/rational/r-hanss/

2.IBM Rational ClearCase-Samba 协同环境的设|和问题解决
http://www-128.ibm.com/developerworks/cn/rational/r-cc-samba/

3.ClearCase Interoperation实例详解
http://www-128.ibm.com/developerworks/cn/rational/06/r-shixl2/index.html

我也别脓了,到这里去扑֐?br />http://www-128.ibm.com/developerworks/cn/views/rational/articles.jsp



eddy liao 2006-07-25 14:01 发表评论
]]>
windows 2003 域服务器的徏?/title><link>http://www.aygfsteel.com/supsky/archive/2006/07/25/59970.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Tue, 25 Jul 2006 04:36:00 GMT</pubDate><guid>http://www.aygfsteel.com/supsky/archive/2006/07/25/59970.html</guid><wfw:comment>http://www.aygfsteel.com/supsky/comments/59970.html</wfw:comment><comments>http://www.aygfsteel.com/supsky/archive/2006/07/25/59970.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/supsky/comments/commentRss/59970.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/supsky/services/trackbacks/59970.html</trackback:ping><description><![CDATA[先把扑ֈ的参考资料发上来Q还不知道有没有用,再整理吧?br /><a >http://www.microsoft.com/china/windowsserver2003/default.mspx</a><br /><h1>Windows Server 2003 部v通用l构分步指南</h1><h2 class="subtitle">W一部分Q将 Windows Server 2003 安装为域控制?br /><a >http://www.microsoft.com/china/technet/prodtechnol/windowsserver2003/technologies/directory/activedirectory/stepbystep/domcntrl.mspx</a><br /></h2><h2 class="subtitle"> </h2><h2 class="subtitle">Win2K安装与服务器配置(?<br /><a >http://article.pchome.net/00/01/79/90/</a><br /><br /><strong>Windows Server 2003中的Active Directory服务</strong><br /><a >http://www.microsoft.com/china/technet/community/columns/profwin/pw0503.mspx</a><br /><br />L配置Windows2003自带MAIL服务?br /><a >http://server.chinabyte.com/91/2394591.shtml</a><br />手把手教您架设Windows2003׃n服务?br /><a >http://server.chinabyte.com/185/2482185.shtml</a></h2><img src ="http://www.aygfsteel.com/supsky/aggbug/59970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/supsky/" target="_blank">eddy liao</a> 2006-07-25 12:36 <a href="http://www.aygfsteel.com/supsky/archive/2006/07/25/59970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在ant中集成checkstyle工具http://www.aygfsteel.com/supsky/archive/2006/07/20/59212.htmleddy liaoeddy liaoThu, 20 Jul 2006 07:51:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/07/20/59212.htmlhttp://www.aygfsteel.com/supsky/comments/59212.htmlhttp://www.aygfsteel.com/supsky/archive/2006/07/20/59212.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/59212.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/59212.htmlcheckstyle 是一个帮助开发者按照某U习惯编?java 代码的工P他实C代码查的自动化,帮助Z从这U繁琐的工作中解攑և来?

默认提供了对 sun ~程规范的支持,但是 checkstyle 是一个具有高可配|性的Q你完全可以Ҏ自己的要求来配置需要检查的内容?br />
有以下这些东?br />\lib\checkstyle-3.1\contrib\checkstyle-noframes.xsl
\lib\checkstyle-3.1\checkstyle-all-3.1.jar
\lib\checkstyle-3.1\sun_checks.xml                    

在build.xml文g中添?br />    <patternset id="java.files.pattern" includes="**/*.java"/>

    <target name="checkstyle" depends="prepare"           依赖prepare target
        description="Check code style for compliance with coding standards">
        <property name="checkstyle.data.dir"
            location="${build.dir}/docs/checkstyle"/>                 存放路径
        <property name="checkstyle.data.file"
            location="${checkstyle.data.dir}/checkstyle.xml"/>     xml文g
        <property name="checkstyle.report.file"
            location="${checkstyle.data.dir}/checkstyle.html"/>   html文g
        <property name="checkstyle.xsl.file"
            location="${checkstyle.dir}/contrib/checkstyle-noframes.xsl"/>   选用的样式表Qcheckstyle.dir为jar包的位置
        <mkdir dir="${checkstyle.data.dir}"/>
        <taskdef resource="checkstyletask.properties" classpath="${checkstyle.jar}"/>  引入jar文g
        <checkstyle config="${checkstyle.dir}/sun_checks.xml"                      选用sun的规范,可以修改q最佛_?br />            failOnViolation="false" failureProperty="checkstyle.failure">
            <fileset dir="src">                                                                   对src目录q行?br />                <patternset refid="java.files.pattern"/>
            </fileset>
            <fileset dir="test">                                                                  对test目录q行?br />                <patternset refid="java.files.pattern"/>
            </fileset>
            <!-- uncomment to print to console as well -->
            <!--formatter type="plain"/-->
            <formatter type="xml" toFile="${checkstyle.data.file}"/>         生成xml文g
        </checkstyle>
        <xslt in="${checkstyle.data.file}" out="${checkstyle.report.file}"
            style="${checkstyle.xsl.file}"/>                                        生成报告,其格式取决于checkstyle.xsl.file
    </target>

如图所C:?列出了所有文Ӟ?列出了所以错?br />
checkstyle1.JPG


checkstyle2.JPG



下面解释了一些常见的输出l果Q以供参考? 
序号            输出内容意义    
1  Type  is  missing  a  javadoc  commentClass    ~少cd说明    
2“{? should  be  on  the  previous  line  “{? 应该位于前一?   
3Methos  is  missing  a  javadoc  commentҎ前面~少javadoc注释    
4Expected  @throws  tag  for  “Exception”在注释中希望有@throws的说?   
5?? Is  preceeded  with  whitespace  ?? 前面不能有空?   
6?? Is  followed  by  whitespace?? 后面不能有空?   
7?? is  not  preceeded  with  whitespace?? 前面~少I格    
8?? is  not  followed  with  whitespace?? 后面~少I格    
9“}? should  be  on  the  same  line“}? 应该与下条语句位于同一?   
10Unused  @param  tag  for  “unused”没有参数“unused”,不需注释    
11Variable  “CA? missing  javadoc变量“CA”缺javadoc注释    
12Line  longer  than  80characters行长度超q?0    
13Line  contains  a  tab  character行含有”tab? 字符    
14Redundant  “Public? modifier冗余的“public? modifier    
15Final  modifier  out  of  order  with  the  JSL  suggestionFinal  modifier的顺序错?   
16Avoid  using  the  ?*? form  of  importImport格式避免使用?*?   
17Redundant  import  from  the  same  package从同一个包中Import内容    
18Unused  import-java.util.listImportq来的java.util.list没有被?   
19Duplicate  import  to  line  13重复Import同一个内?   
20Import  from  illegal  package从非法包? Import内容    
21“while? construct  must  use  “{}”“while? 语句~少“{}?   
22Variable  “sTest1? must  be  private  and  have  accessor  method变量“sTest1”应该是private的,q且有调用它的方?   
23Variable  “ABC? must  match  pattern  “^[a-z][a-zA-Z0-9]*$”变量“ABC”不W合命名规则“^[a-z][a-zA-Z0-9]*$?   
24?? is  followed  by  whitespace?? 后面不能有空? 25?? is  proceeded  by  whitespace?? 前面不能有空?br />25 Line has trailing spaces  行的最后不能有I格

Ҏsun_checks.xml文g的内容,可以?a >http://checkstyle.sourceforge.net/checks.htmlq里查看具体的配|,实现你们的最佛_?br />



eddy liao 2006-07-20 15:51 发表评论
]]>
(转脓)?Jester Ҏ试进行测?/title><link>http://www.aygfsteel.com/supsky/archive/2006/07/19/59000.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Wed, 19 Jul 2006 07:33:00 GMT</pubDate><guid>http://www.aygfsteel.com/supsky/archive/2006/07/19/59000.html</guid><wfw:comment>http://www.aygfsteel.com/supsky/comments/59000.html</wfw:comment><comments>http://www.aygfsteel.com/supsky/archive/2006/07/19/59000.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/supsky/comments/commentRss/59000.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/supsky/services/trackbacks/59000.html</trackback:ping><description><![CDATA[ <a >http://www-128.ibm.com/developerworks/cn/java/j-jester/</a> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="100%"> <h1>?Jester Ҏ试进行测?/h1> <p id="subtitle">试套g有缺Pq不是玩W?/p> <img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" /> </td> <td class="no-print" width="192"> <img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" /> </td> </tr> </tbody> </table> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td width="100%"> <table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="0" width="150" border="0"> <tbody> <tr> <td class="v14-header-1-small">文档选项</td> </tr> </tbody> </table> <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td class="no-padding" width="150"> <table cellspacing="0" cellpadding="0" width="143" border="0"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> <form name="email" action="https://www-128.ibm.com/developerworks/secure/email-it.jsp"> <input type="hidden" value="全面的单元测试套件对健壮的程序是必不可少的。但是如何才能保证测试套件测试了应当试的每件事呢?Ivan Moore ?JUnit 试的测试器 JesterQ擅长发现测试套件的问题Qƈ提供对代码基本结构的深入观察。Elliotte Rusty Harold 介绍?Jester q展C如何用它才能得到最佳结果? name="body" /> <input type="hidden" value="?Jester Ҏ试进行测? name="subject" /> <input type="hidden" value="cn" name="lang" /> <script language="JavaScript" type="text/javascript"> <!-- document.write('<tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="此作为电子邮件发? /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>此作为电子邮件发?/b></a></p></td></tr>'); //--> </script> <tbody> <tr valign="top"> <td width="8"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> </td> <td width="16"> <img height="16" alt="此作为电子邮件发? src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" /> </td> <td width="122"> <p> <a class="smallplainlink" href="javascript:document.email.submit();"> <b> <font color="#5c81a7" size="2">此作为电子邮件发?/font> </b> </a> </p> </td> </tr> <noscript> <tr valign="top"> <td width="8"> <img alt="" height="1" width="8" src="http://www.ibm.com/i/c.gif" /> </td> <td width="16"> <img alt="" width="16" height="16" src="http://www.ibm.com/i/c.gif" /> </td> <td class="small" width="122"> <p> <span id="wmqeeuq" class="ast">未显C需?JavaScript 的文档选项</span> </p> </td> </tr> </noscript> </tbody> </form> </table> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- 03/20/06 updated by gretchen --> <br /> <table cellspacing="0" cellpadding="0" width="150" border="0"> <tbody> <tr> <td class="v14-header-2-small">最新推?/td> </tr> </tbody> </table> <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td class="no-padding" width="150"> <table cellspacing="0" cellpadding="0" width="143" border="0"> <tbody> <tr valign="top"> <td width="8"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> </td> <td> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" /> </td> <td width="125"> <p> <a class="smallplainlink" > <font color="#5c81a7" size="2">Java 应用开发源动力 Q?下蝲免费软gQ快速启动开?/font> </a> </p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <br /> </td> </tr> </tbody> </table> <p>U别: 初</p> <p> <a > <font color="#996699">Elliotte Rusty Harold</font> </a>, 副教? Polytechnic University<br /></p> <p>2005 q?6 ?02 ?/p> <blockquote>全面的单元测试套件对健壮的程序是必不可少的。但是如何才能保证测试套件测试了应当试的每件事呢?Ivan Moore ?JUnit 试的测试器 JesterQ擅长发现测试套件的问题Qƈ提供对代码基本结构的深入观察。Elliotte Rusty Harold 介绍?Jester q展C如何用它才能得到最佳结果?/blockquote> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <p>试先行的开发是极限~程QXPQ中争议最、采用最q泛的部分。到目前为止Q大多数专业 Java E序员都可能捕捉q测?bug。(请参?<a ><font color="#996699">参考资?/font></a> 获得有关“被试传染”的更多信息。) JUnit ?Java C֌事实上的标准试框架Q没有经q全面的 JUnit 试套g试q的pȝ是不完整的。如果您的项目有全面的测试套Ӟ那么恭喜您:您将制作量良好的、有利于工作的Y件。但是大多数代码基础相当复杂。您能确定每个方法都被测试到、每个分支都q入q么Q如果不能,那么当这些方法和分支在生产中执行的时候,应用E序会如何表现呢Q?/p> <p> <a name="N10067"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">代码覆盖</font> </span> </a> </p> <p>对代码进行测试的下一步是?<i>代码覆盖</i> 工具Ҏ试进行度量。代码覆盖是一U查看一套测试覆盖了多少代码的方法。信心的获得Q不仅需要知道测试了E序整体Q还要知道每个方法在全部可能情况下都得到试。传l情况下Q这cd量的执行Ҏ是在试执行时对试q行监视Q可以通过 Java 虚拟试接口(JVMDIQ或 Java 虚拟机工h?QJVMTIQ进行,或者直接处理字节码。一ơ都没有执行q的语句是测试不到的?/p> <p>Clover ?EMMAQ参?<a ><font color="#996699">参考资?/font></a>Q?q类工具采用的这U方法对于发现测试不到的语句很有价?—?但是q不够。知道测试套件没有执行某个语句,可以证明该语句没试到。但是,反过来不成立。如果执行了某一行代码,q不一定代表它得到试。完全有可能存在q样的情况:试q没有检查代码行是否生成正确l果?/p> <p>当然Q没有h会编写测试套件对每个语句的结果都q行验证。在众多的问题当中,q个问题可能会破坏封装。您可能认ؓQ针对特定输入,只有Ҏ中的每一行都操作正确Q方法才会生成预期结果。但是这个假讑ƈ不合理。例如,如果没有试到所有可能输入,也就没有试Cؓ处理辚w情况而设计的代码Q这时会如何呢?有可能还会测试到每行代码Q但有可能遗漏真正的 bug?/p> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"> <a name="N1007F"> <b>q不?/b> </a> <br /> <p>Jester 的方法ƈ不简单。这个工h可能会报告大量假x。例如,它可能把 <code>System.out.println("Copyright 2005 Elliotte Rusty Harold")</code> 语句Ҏ <code>System.out.println("Copyright 3005 Elliotte Rusty Harold")</code> Q然后报告没有破坏发生。但是,假阳性一般很Ҏqo出来。另外,通常也有合适的理由怀疑像q个CZ一L情况是否真的是假x。例如,对于版权日期 3005 是否是测试套件应当通知?bugQ有人可能会有异议?/p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N10091"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">Jester ?/font> </span> </a> </p> <p>q正?Jester 发挥作用的地斏V与 Clover q类传统的代码覆盖工具不同,Jester 不去查看报告了哪行代码。相反,Jester 会修Ҏ代码、重新编译源代码Q然后运行测试套Ӟ查看是否有什么事出错。例如,它会?1 Ҏ 2Q或者把 <code>if (x > y)</code> Ҏ <code>if (false)</code>。如果测试套件的x不够Q没有注意到修改Q那么就说明遗漏了某Ҏ试?/p> <p>我将通过在开源的 Jaxen XPath 工具Q参?<a ><font color="#996699">参考资?/font></a>Q上应用 Jester 而对它进行演C。Jaxen 有一个基?JUnit 的测试套Ӟ而且q个套g的代码覆盖ƈ不完善?/p> <p> <a name="N100A9"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">入门</font> </strong> </span> </a> </p> <p>在运?Jester 之前Q所有对没有修改的源代码的单元测试都必须试通过。如果不是这P那么 Jester 无法知道是不是它的修改造成了破坏。(Z演示Q我不得不修复一?bugQ我q去为它~写了测试用例,但是没有跟踪修复它。) </p> <p>Jester ?IDE 的集成不是特别好Q或者根本不好)Q所以要让测试通过Q重要的是正设|?<code>CLASSPATH</code> 和目录。运行测试套件所需要的命o行对于每个项目都是不同的。因?Jaxen 试使用指向特定试文g的相?URL Q所以它的测试必d jaxen 目录中运行。下面是我最后运?Jaxen 试的方式: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">$ java -classpath ../jester136/jester.jar:target/lib/junit-3.8.1.jar :target/lib/dom4j-core-1.4-dev-8.jar:target/lib/jdom-b10.jar :target/lib/xom-1.0d21.jar:target/test-classes:target/classes junit.textui.TestRunner org.jaxen.JaxenTests</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>在运?Jester 之前Q还需要清楚针Ҏ试套件的一w加限制。除非测试失败,否则不能打印有关 <code>System.err</code> 的Q何内宏VJester 要通过查打印的内容来判断测试是否成功,所以对 <code>System.err</code> 的程序输Z?Jester 弄؜?/p> <p>试套gq行无误之后Q请做一份源代码树的拯。记住,Jester 要向代码故意加入 bugQ所以您可不要冒险在出现问题的情况下遗漏一?bug。(如果您在使用源代码控Ӟ那么q不会是个大问题。如果没有,h停阅L文,立即把代码签?CVS ?Subversion 仓库。)</p> <p> <a name="N100CC"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">q行 Jester</font> </strong> </span> </a> </p> <p>要运?JesterQ在路径中必d时拥?jester.jar ?junit.jarQJUnit 没有?Jester l在一赗需要分别下载)。Jester 在类路径中查扑֮的配|文Ӟ所以必还要把 Jester 的主目录攑֜c\径中。当Ӟq需要添加所试的应用程序需要的其他 JAR。主cL <code>jester.TestTester</code>。传递给q个E序的参数是试应用E序的测试套件名U。(我不得不?Jaxen ~写一个主c,因ؓ它没有包含一个可以运行它的全部测试的cR)如果把全部必要的 JAR 文g和目录都d?<code>CLASSPATH</code> 环境变量Q而不是把它们d?jre/lib/ext 或者用 <code>-classpath</code> 引用它们Q那?Jester 工作h会更加稳定。下面是我针?Jaxen q行初始试的方式:</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">$ export CLASSPATH=src2/java/main:../jester136/jester.jar:../jester136 :target/lib/junit-3.8.1.jar:target/lib/dom4j-core-1.4-dev-8.jar :target/lib/jdom-b10.jar:target/lib/jdom-b10.jar:target/lib/xom-1.0d21.jar :target/test-classes:target/classes $ java jester.TestTester org.jaxen.JaxenTests src2/java/main </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Jester q行很慢Q即使检一个文件也是如此。它昄一个进度对话框Q如?1 所C,q在 <code>System.out</code> 上打印输出,让您知道它在做的工作Qƈ向您保证它ƈ没有完全挂v?/p> <br /> <a name="figure1"> <b>?1. Jester q度</b> </a> <br /> <img height="237" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-jester/jester.gif" width="600" /> <br /> <p>如果在第一ơ运行若q分钟(或者时间够运行完整的试套gQ甚x长)之后Q什么输Z没有看到Q那?Jester 可能 <i>实</i> 挂v了,q很可能是因为类路径的问题。如果每件事都进行顺利,那么应当看到像清?1 所C的输出Q?</p> <br /> <a name="listing1"> <b>清单 1. Jester 输出</b> </a> <br /> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> Use classpath: src2/java/main:../jester136/jester.jar :../jester136:target/lib/junit-3.8.1.jar:target/lib/dom4j-core-1.4-dev-8.jar :target/lib/jdom-b10.jar:target/lib/jdom-b10.jar:target/lib/xom-1.0d21.jar :target/test-classes:target/classes ... src2/java/main/org/jaxen/BaseXPath.java - changed source on line 192 (char index=7757) from 1 to 2 answer.size() == ?1 ) { Object first = answ src2/java/main/org/jaxen/BaseXPath.java - changed source on line 691 (char index=24848) from 0 to 1 return results.get( ?0 ); } } lots more output... src2/java/main/org/jaxen/BaseXPath.java - changed source on line 691 (char index=24848) from 0 to 1 return results.get( ?0 ); } } 10 mutations survived out of 11 changes. Score = 10 took 1 minutes</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>从清?1 中可以看刎ͼ<code>BaseXPath</code> 没有得到很好的测试。Jester 对类q行?11 修改,而只有一w成试p|。有些修Ҏ假阳性,但是 11 处修改肯定不应当只报?1 处?/p> <p>下一步是在不破坏试套g的情况下查看 Jester 改变的代码,看看是否需要ؓ它编写测试。Jester ?GUI 中显C它q行的修改,?<a ><font color="#996699">?1</font></a> 所C(它不能在无h控制的情况下q行Q这有点烦hQ,在控制台上打印输出,?<a ><font color="#996699">清单 1</font></a> 所C,q生?XML 文gQ文件中是没有生媄响的修改列表Q如清单 2 所C: </p> <br /> <a name="listing2"> <b>清单 2. Jester XML 输出</b> </a> <br /> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> <JesterReport> <JestedFile fileName="src2/java/main/org/jaxen/BaseXPath.java" absolutePathFileName= "/Users/elharo/Documents/articles/jester/jaxen/src2/java/main/org/jaxen/BaseXPath.java" numberOfChangesThatDidNotCauseTestsToFail="8" numberOfChanges="11" score="28"> <ChangeThatDidNotCauseTestsToFail index="7691" from="if (" to="if (true ||"/> <ChangeThatDidNotCauseTestsToFail index="7691" from="if (" to="if (false &&"/> <ChangeThatDidNotCauseTestsToFail index="7703" from="!=" to="=="/> <ChangeThatDidNotCauseTestsToFail index="7754" from="==" to="!="/> <ChangeThatDidNotCauseTestsToFail index="7757" from="1" to="2"/> <ChangeThatDidNotCauseTestsToFail index="7826" from="if (" to="if (true ||"/> <ChangeThatDidNotCauseTestsToFail index="7826" from="if (" to="if (false &&"/> <ChangeThatDidNotCauseTestsToFail index="24749" from="if (" to="if (false &&"/> </JestedFile></JesterReport></font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Jester 的行h告通常不是个好ҎQ所以最好是在控制台输出中查找修改的代码。下面是 <a ><font color="#996699">清单 1</font></a> 的报告中的修改: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">src2/java/main/org/jaxen/BaseXPath.java - changed source on line 691 (char index=24848) from 0 to 1 return results.get( ?0 ); } }</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>在这个方法中Q这个修Ҏ在类的结束处Q?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">protected Object selectSingleNodeForContext(Context context) throws JaxenException { List results = selectNodesForContext( context ); if ( results.isEmpty() ) { return null; } return results.get( 0 ); }</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Ҏ试套件迅速查找之后发玎ͼ实际上没有测试调?<code>selectSingleNodeForContext</code>。所以下一步就是ؓq个Ҏ~写一个测试。这个方法是 protected 的方法,所以测试不能直接调用它。有旉要编写一个子c(通常作ؓ内部c)来测?protected 的方法。但是在q个例子中,E做一Ҏ查就很快发现q个Ҏ由同一个类中的两个 public ҎQ?code>stringValue</code> ?<code>numberValue</code>Q直接调用。所以也可以用这两个Ҏ来测试它Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> public void testSelectSingleNodeForContext() throws JaxenException { BaseXPath xpath = new BaseXPath("1 + 2"); String stringValue = xpath.stringValueOf(xpath); assertEquals("3", stringValue); Number numberValue = xpath.numberValueOf(xpath); assertEquals(3, numberValue.doubleValue(), 0.00001); }</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>最后一步是q行试用例Q确定它通过。下面是l果Q?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">java.lang.NullPointerException at org.jaxen.function.StringFunction.evaluate(StringFunction.java:121) at org.jaxen.BaseXPath.stringValueOf(BaseXPath.java:295) at org.jaxen.BaseXPathTest.testSelectSingleNodeForContext(BaseXPathTest.java:23)</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Jester 捕捉C?bugQ方法没有像预期的那样工作。更有趣的是Q对 bug 的调查揭C出潜在的设计缺陗?code>BaseXPath</code> cd能更适合作ؓ抽象c而不是具体类。我发誓Q我q不是特意挑选这个示例来公开q个 bug。我?<code>BaseXPath</code> 开始只是因为它是顶U?org.jaxen 包的W一个类Q而且我选择 <code>selectSingleNodeForContext</code> 作ؓ所试的方法也只是因ؓ它是 Jester 报告的最后一个错误。我真的认ؓq个Ҏ没有什么问题,但是我错了。如果某些事没有l过试Q那么就应当假设它是有问题的。Jester 会告诉您Z什么问题?/p> <p>下一步显而易见:修复 bug。(L保同时对 Jester 正在处理的源树拷贝和实际树中?bug q行了修复。)然后QP?—?针对q个c重新运?JesterQ直CQ何修攚w不能通过Q或者可以通过的修攚w是不相关的。在我ؓq个 bug d试Qƈ修复Q之后,Jester 报?11 个修改中只有 8 个没有检到Q如 <a ><font color="#996699">清单 2</font></a> 所C。这在调试中是经常出现的事:修复了一个问题就修复Q或者暴露了Q另外几个?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N10172"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">Jester 的性能</font> </span> </a> </p> <p>因ؓ Jester 重新~译代码基,而且要ؓ自己做的每个修改都重新运行测试套Ӟ所以它的运行要?Clover q样的传l工h得多。因此,Ҏ能加以x是很重要的。可以用许多技术加?Jester 的运行?</p> <p>首先Q如果编译在 Jester 执行旉中占了显著部分,那么请尝试用一个更快的~译器。许多用户都报告采用 Jikes 代替 Javac 后速度有显著提高(参阅 <a ><font color="#996699">参考资?/font></a>Q。可以在 Jester ȝ录中?jester.cfg 文g中修?Jester 使用的编译命令?/p> <p>W二Q剖析和优化试套g。一般情况下Qh们对单元试q行的速度没太注意Q但是如果乘?Jester 上千ơ执行测试套件的ơ数Q那么Q何节U都会非常显著。具体来_要在试套g中查扑֜正常代码中不会出现的问题。JUnit 会重新初始化每个执行Ҏ的全部字D,所以如果不是测试类的每个方法都用的字段Q那么把试数据从字D中拿出来放在本地变量中Q可以显著提高速度。如果Ş成的代码副本不合您的风格Q请试把测试套件分成更、更模块化的c,以便所有的初始数据可以在全部测试方法之间共享?/p> <p>W三Q重新组l测试套件的 <code>suite</code> ҎQ以便最脆弱的测试(修改之后最有可能出错的Q在不太脆弱的测试之前运行。只?Jester 发现一个测试失败,׃l止q行Q所以尽早失败可以短路大量耗时的额外测试?/p> <p>W四Q出于相似的原因Q当试p|的机会差不多Ӟ把最快的试攑֜W一位。按照大概的执行旉l测试排序。只在内存中执行的测试在讉K盘的测试之前,讉K盘的测试在讉K LAN 的测试之前,讉K LAN 的测试在讉K Internet 的测试之前。如果有些测试特别慢Q试试去掉它们,即便q会增加假阳性的数量。在 XOM Q一个用 Java 语言处理 XML ?APIQ的试套g中,?50 个测试类中,只有很少的几个就占据?90% 以上的执行时间。在试的时候清除这些类可以带来 10 倍的性能提升?/p> <p>最后,也是最重要的,是不要一ơ测试整个代码基。每ơ把试限制在一个类上,而且只运行能够暴露这个类的覆盖不的试。可能需要更长时间来试每个c,但是用这U方法,几乎可以立即填补不、修?bugQ而不必ؓ Jester 的一ơ运行完成等上好几天?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N10192"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">l束?/font> </span> </a> </p> <p>Jester 是聪明的E序员的工具包中一个重要的附加。它可以发现其他工具不能发现的代码覆盖不Iq会直接变成发现和修?bug。?Jester 对代码基q行试Q可以制造出更强壮的软g?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="resources"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">参考资?</font> </span> </a> </p> <ul> <li>您可以参阅本文在 developerWorks 全球站点上的 <a target="_blank"><font color="#5c81a7">英文原文</font></a>?br /><br /></li> <li>?SourceForge 下蝲 <a ><font color="#5c81a7">Jester</font></a>?br /><br /></li> <li>得到 <a ><font color="#5c81a7">test infected</font></a>?br /><br /></li> <li> <a > <font color="#5c81a7">JUnit</font> </a> ?Java 代码事实上的标准单元试框架Q也?Jester 依赖的框架?br /><br /></li> <li>在本文中作ؓCZ?<a ><font color="#5c81a7">Jaxen</font></a> 目是一个用?Java 语言的开?XPath 引擎Q适用于许多不同的对象模型?br /><br /></li> <li> <a > <font color="#5c81a7">Clover</font> </a> 是一个更传统的测试覆盖工P?Jester 的有益补充。它?Jester 更容易用,也快得多Q但是它只能试在测试期间执行的代码Q而不是它真正要测试的代码?br /><br /></li> <li> <a > <font color="#5c81a7">EMMA</font> </a> 是一个免贏V开源的代码覆盖工具。请学习面向 Java E序员的各种不同?<a ><font color="#5c81a7">开源单元测试工?/font></a> ?<a ><font color="#996699">开源代码覆盖工?/font></a> 的更多内宏V?br /><br /></li> <li>请阅?Dave Thomas ?Andy Hunt ?<a ><font color="#5c81a7"><i>Pragmatic Unit Testing in Java With JUnit</i></font></a>QPragmatic Bookshelf, 2003Q?br /><br /></li> <li>Dennis M. Sosnoski 通过介绍开源的 <a ><font color="#5c81a7">Hansel</font></a> ?<a ><font color="#5c81a7">Gretel</font></a> 代码覆盖工具Q?a ><font color="#5c81a7">开?/font></a> ?<a ><font color="#5c81a7">Classworking 工具?/font></a> pd?br /><br /></li> <li>David Carew ?Sandeep Desai 撰写的?a ><font color="#5c81a7">Keeping critters out of your code: How to use WebSphere and JUnit to prevent programming bugs</font></a>”(developerWorks, 2003 q?6 月)Q介l了采用 XP Ҏq行试?br /><br /></li> <li>Malcolm Davis 撰写的?a ><font color="#5c81a7">利用 Ant ?JUnit q行增量开?/font></a>”(developerWorksQ?000 q?11 月)Q解释了如何?JUnit 集成到自q目中?br /><br /></li> <li>Eric Allen ?Roy Miller 在他们各自的专栏 <a ><font color="#5c81a7">诊断 Java 代码</font></a> ?<a ><font color="#5c81a7">揭开极端~程的神U面U?/font></a> 中频J地涉及到单元测试?br /><br /></li> <li>Erik Hatcher 撰写的?a ><font color="#5c81a7">让编译和试q程自动?/font></a>”(developerWorksQ?001 q?8 月)Q介l了如何把增量测试和持箋构徏l合C个自动的q程中?br /><br /></li> <li> <a > <font color="#5c81a7">Testdriven.com</font> </a> 是一个关于测试驱动开发的文章和资源的全面集合?br /><br /></li> <li> <a > <font color="#5c81a7">Jikes</font> </a> 是一个用 C ~写的开源的 Java ~译器,q行h?javac 快得多?br /><br /></li> <li>?developerWorks <a ><font color="#5c81a7">Java 技术专?/font></a> 可以扑ֈ Java ~程各方面的文章?br /><br /></li> <li>误?<a ><font color="#5c81a7">Developer Bookstore</font></a>Q获得技术书c的完整列表Q其中包括数百本 <a ><font color="#5c81a7">Java 相关主题</font></a> 的图书?br /><br /></li> <li>通过参与 <a ><font color="#5c81a7">developerWorks blogs</font></a> 加入 developerWorks C֌?br /></li> </ul> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="author"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">关于作?/font> </span> </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td colspan="3"> <font face="Arial" size="4"> <img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> </font> </td> </tr> <tr valign="top" align="left"> <td> <p> <font face="Arial" size="4"> </font> </p> </td> <td> <font face="Arial" size="4"> <img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /> </font> </td> <td width="100%"> <p>Elliotte Rusty Harold 来自新奥良Q现在他q定期返回新奥尔良研I一盆秋c但是,他和d Beth 及他们的猫咪 CharmQ以夸克命名Q和 MarjorieQ以他的x为名Q,定居在布鲁克林附q的 Prospect Heights。他?Polytechnic 大学计算机科学的副教授,他在该校讲授 Java 和面向对象编E。他?Web 站点 <a ><font color="#5c81a7">Cafe au Lait</font></a> 已经成ؓ Internet 上最行的独?Java 站点之一Q他的分站点 <a ><font color="#5c81a7">Cafe con Leche</font></a> 已经成ؓ最行?XML 站点之一。他的书包括 <a ><font color="#5c81a7"><i>Effective XML</i></font></a>?a ><font color="#5c81a7"><i>Processing XML with Java</i></font></a>?a ><font color="#5c81a7"><i>Java Network Programming</i></font></a>?<a ><font color="#5c81a7"><i>The XML 1.1 Bible</i></font></a>。他目前在开发处?XML ?XOM API ?XQuisitor GUI 查询工具?/p> </td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/supsky/aggbug/59000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/supsky/" target="_blank">eddy liao</a> 2006-07-19 15:33 <a href="http://www.aygfsteel.com/supsky/archive/2006/07/19/59000.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Open Source Code Coverage Tools in Javahttp://www.aygfsteel.com/supsky/archive/2006/07/19/58999.htmleddy liaoeddy liaoWed, 19 Jul 2006 07:29:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/07/19/58999.htmlhttp://www.aygfsteel.com/supsky/comments/58999.htmlhttp://www.aygfsteel.com/supsky/archive/2006/07/19/58999.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/58999.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/58999.htmlhttp://java-source.net/open-source/code-coverage

Quilt

Quilt is a Java software development tool that measures coverage , the extent to which unit testing exercises the software under test. It is optimized for use with the JUnit unit test package, the Ant Java build facility, and the Maven project management toolkit.

Go To Quilt

EMMA

EMMA is an open-source toolkit for measuring and reporting Java code coverage. EMMA distinguishes itself from other tools by going after a unique feature combination: support for large-scale enterprise software development while keeping individual developer's work fast and iterative at the same time. Every developer on your team can now get code coverage for free and they can get it fast! EMMA is so lightweight developers can use it during the process of writing tests instead of waiting for a "test build". This gets code coverage where it belongs: helping with design and implementation before the code is checked in.

Go To EMMA

NoUnit

NoUnit allows you to see how good your JUnit tests are. It generates a report from your code to graphically show you how many of your project's methods are being tested , and how well.

Go To NoUnit

InsECT

InsECT which stands for Instrumentation Execution Coverage Tool, is a system developed in Java to obtain coverage information for Java programs. InsECT instruments (inserts instructions into) Java class files at the bytecode level with probes to report information about a system at runtime. The goal of InsECT is to provide detailed coverage information about Java programs by taking into full account the object-oriented behavior and language features of Java. Furthermore, as an open-source project, InsECT is designed to be extensible for use in a wide variety of dynamic analyses. InsECT utilizes the Byte Code Engineering Library.

Go To InsECT

Hansel

Hansel is an extension to JUnit that adds code coverage testing to the testing framework.

Go To Hansel

Jester

Jester finds code that is not covered by tests. Jester makes some change to your code, runs your tests, and if the tests pass Jester displays a message saying what it changed. Jester includes a script for generating web pages that show the changes made that did not cause the tests to fail.

Go To Jester

JVMDI Code Coverage Analyser

This small utility is a shared library which when loaded into a Java VM (1.4+) which supports JVMDI will record all the lines of code executed. This is a relatively coarse coverage method, but good enough for a lot of purposes.

Go To JVMDI Code Coverage Analyser

GroboCodeCoverage

GroboCodeCoverage is a 100% Pure Java implementation of a Code Coverage tool. It uses Jakarta's BCEL platform to post-compile class files to add logging statements for tracking coverage.

Go To GroboCodeCoverage

jcoverage/gpl

jcoverage/gpl is a free code-coverage tool for Java?programmers that allows them to measure the effectiveness of their Java tests and how much of a software program's code has been tested. jcoverage/gpl identifies how many times each line of code in your application has been executed and you can see which parts of your software remain untested. After instrumenting your code and running your tests, a report is generated allowing you to view information coverage figures from a project level right down to the individual line of code. This process is called 'code coverage'.

Go To jcoverage/gpl

JBlanket

JBlanket is a tool for assessing and improving method coverage of unit test cases. It is integrated with JUnit and Ant.

Go To JBlanket

Cobertura

Cobertura is a free Java tool that calculates the percentage of code accessed by tests. It can be used to identify which parts of your Java program are lacking test coverage. It is based on jcoverage. Cobertura produces very nice reports. It works by instrumenting Java bytecode after it has been compiled.

Go To Cobertura

Coverlipse

An eclipse plugin for code coverage visualization of JUnit Tests. Supported coverages include block coverage and all-uses coverage (Data Flow Analysis). License is CPL (Common Public License)

Go To Coverlipse



eddy liao 2006-07-19 15:29 发表评论
]]>
(转脓)q求代码质量: 监视圈复杂度http://www.aygfsteel.com/supsky/archive/2006/07/19/58988.htmleddy liaoeddy liaoWed, 19 Jul 2006 07:06:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/07/19/58988.htmlhttp://www.aygfsteel.com/supsky/comments/58988.htmlhttp://www.aygfsteel.com/supsky/archive/2006/07/19/58988.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/58988.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/58988.htmlhttp://www-128.ibm.com/developerworks/cn/java/j-cq03316/


q求代码质量: 监视圈复杂度

当代码复杂度出惛_时该如何?/p>

developerWorks
文档选项
此作为电子邮件发? src=

此作为电子邮件发?/font>

未显C需?JavaScript 的文档选项

讨论


最新推?/td>

Java 应用开发源动力 Q?下蝲免费软gQ快速启动开?/font>


U别: 初

Andrew Glover , 总裁, Stelligent Incorporated

2006 q?4 ?25 ?/p>

如果复杂度与~陷紧密相关Q那么监视代码库的复杂度g是很有意义吗QAndrew Glover 展C如何用简单的代码度量工具和基?Java?的工h监视圈复杂度 (cyclomatic complexity)?/blockquote>

每位开发h员对代码质量的含义都有着自己的看法,q且大多Ch对如何查扄写欠佳的代码也有自己的想法。甚x?i>代码味道Qcode smellQ?/i> 也已q入大众词汇表,成ؓ描述代码需要改q的一U方式?/p>
圈什么?

关于q篇文章和代码质量主题的M其他文章的问题,误问由 Andrew Glover L?Improve your Java Code Quality 讨论论坛?

代码味道通常由开发h员直接判定,有趣的是Q它是许多代码注释综合在一L味道。一些h声称公正的代码注释是好事情,而另一些h声称代码注释只是解释q于复杂的代码的一U机制。显ӞJavadocs?很有用,但是多少内嵌注释才以维护代码?如果代码已经~写得够好Q它q需要解释自己吗Q?/p>

q告诉我们,代码味道是一U评C码的机制Q它h主观性。我怿Q那些闻h味道p透了的代码可能是其他人曾l编写的最好的代码。以下这些短语听h是不是很熟悉Q?

是的Q它初看h有点乱,但是您要看到它多么可扩展Q!

或?/p>

它让您感到迷惑,但显然您不了解它的模式?/i>

我们需要的是客观评C码质量的ҎQ某U可以决定性地告诉我们正在查看的代码是否存在风险的东西。不您是否怿Q这U东西确实存在!用来客观评估代码质量的机制已l出C一D|间了Q只是大多数开发h员忽略了它们。这些机制被UCؓ代码度量 (code metric)?/p>

代码度量的历?/font>

几十q前Q少数几个非常聪明的人开始研I代码,希望定义一个能够与~陷兌的测量系l。这是一个非常有的dQ通过研究?bug 代码中的模式Q他们希望创建正式的模型Q然后可以评估这些模型,在缺?i>成ؓ~陷之前 捕获它们?/p>

在这条研I之路上Q其他一些非常聪明的Z军_通过研究代码看看他们是否可以量开发h员的生效率。对每位开发h员的代码行的l典度量g只停留在表面上:

Joe 生的代码要?Bill 多,因此 Joe 生率更高一些,值得我们花钱聘请q样的h。此外,我注意到 Bill l常在饮水机辚w晃,我认为我们应该解?Bill?/i>

但是q种生率度量在实践中是非常令h失望的,主要是因为它Ҏ被滥用。一些代码测量包括内嵌注释,q且q种度量实际上受益于剪切_脓式开?(cut-and-paste style development)?

Joe ~写了许多缺P其他每条~陷也都是由他间接造成的。我们不该解?BillQ他的代码实际上是免的?/i>

可以预见Q生产率研究被证实是非常不准的Q但在管理团?(management body) q泛使用q种生率度量以期了解每个h的能力的价g前,情况q如此。来自开发h员社区的痛苦反应是有理由的,对于一些h而言Q那U痛苦感觉从未真正走q?/p>

未经雕琢的钻?/font>

管存在q些p|Q但在那些复杂度与缺L怺关系的研I中仍然有一些美玉。大多数开发h员忘记进行代码质量研I已有很长一D|间了Q但对于那些仍正在钻研的言Q特别是如果您也正在求代码质量而努力钻研)Q会在今天的应用中发现这些研I的价倹{例如,您曾注意C些长的方法有旉以理解吗Q是否曾无法理解嵌套很深的条件从句中的逻辑Q您的避开q类代码的本能是正确的。一些长的方法和带有大量路径的方?i>?/i> 难以理解的,有趣的是Q这cL法容易导致缺陗?

我将使用一些例子展C我要表辄意思?/p>



回页?/font>


数字的vz?/font>

研究昄Q^均每人在其大脑中大约能够处理 7Q?Q位数字。这是Z么大多数人可以很Ҏ地记住电话号码,但却很难C大于 7 位数字的信用卡号码、发次序和其他数字序列的原因?/p>

此原理还可以应用于代码的理解上。您以前大概已经看到q类似清?1 中所C的代码片段Q?/p>
清单 1. 适用记忆数字的原?/b>
												
														if (entityImplVO != null) {
  List actions = entityImplVO.getEntities();
  if (actions == null) {
     actions = new ArrayList();
  }
  Iterator enItr = actions.iterator();
  while (enItr.hasNext()) {
    entityResultValueObject arVO = (entityResultValueObject) actionItr
     .next();
    Float entityResult = arVO.getActionResultID();
    if (assocPersonEventList.contains(actionResult)) {
      assocPersonFlag = true;
    }
    if (arVL.getByName(
      AppConstants.ENTITY_RESULT_DENIAL_OF_SERVICE)
         .getID().equals(entityResult)) {
      if (actionBasisId.equals(actionImplVO.getActionBasisID())) {
        assocFlag = true;
      }
    }
    if (arVL.getByName(
     AppConstants.ENTITY_RESULT_INVOL_SERVICE)
      .getID().equals(entityResult)) {
     if (!reasonId.equals(arVO.getStatusReasonID())) {
       assocFlag = true;
     }
   }
 }
}else{
  entityImplVO = oldEntityImplVO;
}


												
										

清单 1 展示?9 条不同的路径。该代码片段实际上是一?350 多行的方法的一部分Q该Ҏ展示?41 条不同的路径。设想一下,如果您被分配一Q务,要修ҎҎ以添加一Ҏ功能。如果您该方法不是您~写的,您认为您能只做必要的更改而不会引入Q何缺陷吗Q?/p>

当然Q您应该~写一个测试用例,但您会认试用例能将您的特定更改在条件从句的h中隔v来吗Q?





回页?/font>


量路径复杂?/font>

圈复杂度 是在我前面提到的那些研究期间开创的Q它可以_地测量\径复杂度。通过利用某一Ҏ路由不同的\径,q一Z整数的度量可适当地描q方法复杂度。实际上Q过dq的各种研究已经定Q圈复杂度(?CCQ大?10 的方法存在很大的出错风险。因?CC 通过某一Ҏ来表C\径,q是用来定某一Ҏ到达 100% 的覆盖率需要多测试用例的一个好Ҏ。例如,以下代码Q您可能记得本系列的W一文章中使用q它Q包含一个逻辑~陷Q?


清单 2. PathCoverage 有一个缺P
												
														public class PathCoverage {
  public String pathExample(boolean condition){
    String value = null;
    if(condition){
      value = " " + condition + " ";
    }
    return value.trim();
  }
}

												
										

作ؓ响应Q我可以~写一个测试,它将辑ֈ 100% 的行覆盖率:


清单 3. 一个测试生完全覆盖!
												
														import junit.framework.TestCase;

public class PathCoverageTest extends TestCase {
  public final void testPathExample() {
    PathCoverage clzzUnderTst = new PathCoverage();
    String value = clzzUnderTst.pathExample(true);
    assertEquals("should be true", "true", value);
  }       
}

												
										

接下来,我将q行一个代码覆盖率工具Q比?CoberturaQƈ获得如?1 中所C的报告Q?/p>
?1. Cobertura 报告

哦,有点失望。代码覆盖率报告指示 100% 的覆盖率Q但我们知道q是一个误对{?/p>

二对?/font>

注意Q清?2 中的 pathExample() Ҏ有一个gؓ 2 ?CCQ一个用于默认\径,一个用?if 路径Q。?CC 作ؓ更精的覆盖率测量尺度意味着W二个测试用例是必需的。在q里Q它是不进?if 条g语句而采用的路径Q如清单 4 中的 testPathExampleFalse() Ҏ所C:


清单 4. 沿着较少采用的\径向?/b>
												
														import junit.framework.TestCase;

public class PathCoverageTest extends TestCase {
  
  public final void testPathExample() {
    PathCoverage clzzUnderTst = new PathCoverage();
    String value = clzzUnderTst.pathExample(true);
    assertEquals("should be true", "true", value);
  } 

  public final void testPathExampleFalse() {
    PathCoverage clzzUnderTst = new PathCoverage();
    String value = clzzUnderTst.pathExample(false);
    assertEquals("should be false", "false", value);
  } 
}

												
										

正如您可以看到的Q运行这个新试用例会生一个o厌的 NullPointerException。在q里Q有的是我们可以用圈复杂?i>而不?/i> 使用代码覆盖率来扑ևq个~陷。代码覆盖率指示我们已经在一个测试用例之后完成了此操作,?CC 却会我们~写额外的测试用例。不太坏,是吧Q?/p>

q运的是Q这里的试中的Ҏ有一个gؓ 2 ?CC。设想一下该~陷被隐藏在 CC ?102 的方法中的情c祝您好q找到它Q?/p>



回页?/font>


图表上的 CC

Java 开发h员可使用一些开放源码工h报告圈复杂度。其中一个这L工具?JavaNCSSQ它通过?Java 源文件来定Ҏ和类的长度。此外,此工兯攉代码库中每个Ҏ的圈复杂度。通过利用 Ant d?Maven 插g配置 JavaNCSSQ可以生成一个列Z下内容的 XML 报告Q?/p>

  • 每个包中的类、方法、非注释代码行和各种注释样式的L?br />
  • 每个cM非注释代码行、方法、内部类?Javadoc 注释的L?br />
  • 代码库中每个Ҏ的非注释代码行的L和圈复杂度?/li>

该工具附带了量样式表,可以使用它们来生成ȝ数据?HTML 报告。例如,?2 阐述?Maven 生成的报告:


?2. Maven 生成?JavaNCSS 报告

此报告中带有 Top 30 functions containing the most NCSS 标签的部分详l描qC代码库中最长的ҎQ顺便提一句,该方?i>几乎L 与包含最大圈复杂度的Ҏ相关联。例如,该报告列Z DBInsertQueueupdatePCensus() ҎQ因为此Ҏ的非注释行L?283Q圈复杂度(标记?CCNQؓ 114?/p>

正如上面所演示的,圈复杂度是代码复杂度的一个好的指C器Q此外,它还是用于开发h员测试的一个极好的衡量器。一个好的经验法则是创徏数量与将被测试代码的圈复杂度值相{的试用例。在?2 中所见的 updatePCensus() Ҏ中,需?114 个测试用例来辑ֈ完全覆盖?/p>



回页?/font>


分而治?/font>

在面ҎC高圈复杂度值的报告ӞW一个行动是验所有相应测试的存在。如果存在一些测试,试的数量是多少Q除了极数代码库以外,几乎所有代码库实际上都?114 个测试用例用?updatePCensus() ҎQ实际上Qؓ一个方法编写如此多的测试用例可能会p很长旉Q。但即是很的一点进步,它也是减方法中存在~陷风险的一个伟大开始?/p>

如果没有M相关的测试用例,昄需要测试该Ҏ。您首先惛_的可能是Q到重构的时间了Q但q样做将打破W一个重构规则,卛_~写一个测试用例。先~写试用例会降低重构中的风险。减圈复杂度的最有效方式是隔M码部分,它们放入新的方法中。这会降低复杂度QҎ更容易管理(因此更容易测试)。当Ӟ随后应该试那些更小的方法?/p>

在持l集成环境中Q?i>随时间变?/i> 评估Ҏ的复杂度是有可能的。如果是W一ơ运行报告,那么您可以监视方法的复杂度值或M相关的成长度QgrowthQ。如果在 CC 中看C个成长度Q那么您可以采取适当的动作?/p>

如果某一Ҏ?CC 值在不断增长Q那么您有两个响应选择Q?/p>

  • 保相关试的健h况仍然表Cؓ减少风险?
  • 评估重构Ҏ减少M长期l护问题的可能性?/li>

q要注意的是QJavaNCSS 不是惟一用于 Java q_促进复杂度报告的工具。PMD 是另一个分?Java 源文件的开源项目,它有一pd的规则,其中之一是报告圈复杂度。CheckStyle 是另一个具有类似的圈复杂度规则的开放源码项目。PMD ?CheckStyle 都有 Ant d?Maven 插gQ请参阅 参考资?/font>Q从那里获得关于x为止讨论的所有工L更多信息。)





回页?/font>


使用复杂度度?/font>

因ؓ圈复杂度是如此好的一个代码复杂度指示器,所以测试驱动的开?(test-driven development) 和低 CC g间存在着紧密相关的联pR在~写试Ӟ注意Q我没有暗示?i>W一?/i>Q,开发h员通常們֐于编写不太复杂的代码Q因?i>复杂的代码难以测?/i>。如果您发现自己难以~写某一代码Q那么这是一U警C,表示正在试的代码可能很复杂。在q些情况下,TDD 的简短的 “代码、测试、代码、测试?循环导致重构,而这l驱佉K复杂代码的开发?/p>

所以,在用遗留代码库的情况下Q测量圈复杂度特别有价倹{此外,它有助于分布式开发团队监?CC |甚至对具有各U技术别的大型团队也是如此。确定代码库中类Ҏ?CC q连l监视这些值将使您的团?i>在复杂问题出现时 抢先处理它们?/p>



回页?/font>


参考资?

学习
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文 ?

  • ?a >q求代码质量: 不要被覆盖报告所qh”(Andrew GloverQdeveloperWorksQ?006 q?1 月)Q测试覆盖率的测量是否让您误入歧途?扑և新系列中的第一文章!

  • ?a >试优先 Ruby ~程”(Pat EylerQdeveloperWorksQ?005 q?5 月)Qtest-first 开发中的一个简单练习,其中包括关于重构的讨论?br />
  • ?a >?Cobertura 量试覆盖?/font>”(Elliotte Rusty HaroldQdeveloperWorksQ?005 q?5 月)Q关于?Cobertura 来测量测试覆盖率的初U读物?br />
  • Java 技术专?/font> Q数癄 Java ~程各方面的文章?/li>

获得产品和技?/b>
  • JavaNCSS Q适用?Java q_的一个源代码量套g?br />
  • PMD Q这个流行的开放源码工h?Java 代码以发现问题?br />
  • CheckStyle Q来?SourceForge 的另一?Java 分析工具?br />

讨论




回页?/font>


关于作?/font>

Andrew Glover ?Stelligent Incorporated 的总裁Q该公司采用有效的开发h员测试策略和持箋集成技术(让团队能够尽早且l常地监视代码质量)帮助其他公司解决软g开发质量问题。他q是 Java Testing PatternsQWileyQ?004 q?9 月)一书的合著者?



eddy liao 2006-07-19 15:06 发表评论
]]>Q{_?Cobertura 量试覆盖?/title><link>http://www.aygfsteel.com/supsky/archive/2006/07/19/58967.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Wed, 19 Jul 2006 04:52:00 GMT</pubDate><guid>http://www.aygfsteel.com/supsky/archive/2006/07/19/58967.html</guid><wfw:comment>http://www.aygfsteel.com/supsky/comments/58967.html</wfw:comment><comments>http://www.aygfsteel.com/supsky/archive/2006/07/19/58967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/supsky/comments/commentRss/58967.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/supsky/services/trackbacks/58967.html</trackback:ping><description><![CDATA[ <a >http://www-128.ibm.com/developerworks/cn/java/j-cobertura/</a> <br /> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="100%"> <h1>?Cobertura 量试覆盖?/h1> <p id="subtitle">扑և隐藏 bug 的未试到的代码</p> <img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" /> </td> <td class="no-print" width="192"> <img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" /> </td> </tr> </tbody> </table> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td width="100%"> <table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="0" width="150" border="0"> <tbody> <tr> <td class="v14-header-1-small">文档选项</td> </tr> </tbody> </table> <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td class="no-padding" width="150"> <table cellspacing="0" cellpadding="0" width="143" border="0"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> <form name="email" action="https://www-128.ibm.com/developerworks/secure/email-it.jsp"> <input type="hidden" value="Cobertura 是一U开源工P它通过基本的代码Qƈ观察在测试包q行时执行了哪些代码和没有执行哪些代码,来测量测试覆盖率。除了找出未试到的代码q发?bug 外,Cobertura q可以通过标记无用的、执行不到的代码来优化代码,q可以提?API 实际操作的内部信息。Elliotte Rusty Harold 与您分享如何利用代码覆盖率的最佛_跉|使用 Cobertura? name="body" /> <input type="hidden" value="?Cobertura 量试覆盖? name="subject" /> <input type="hidden" value="cn" name="lang" /> <script language="JavaScript" type="text/javascript"> <!-- document.write('<tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="此作为电子邮件发? /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>此作为电子邮件发?/b></a></p></td></tr>'); //--> </script> <tbody> <tr valign="top"> <td width="8"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> </td> <td width="16"> <img height="16" alt="此作为电子邮件发? src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" /> </td> <td width="122"> <p> <a class="smallplainlink" href="javascript:document.email.submit();"> <b> <font color="#5c81a7" size="2">此作为电子邮件发?/font> </b> </a> </p> </td> </tr> <noscript> <tr valign="top"> <td width="8"> <img alt="" height="1" width="8" src="http://www.ibm.com/i/c.gif" /> </td> <td width="16"> <img alt="" width="16" height="16" src="http://www.ibm.com/i/c.gif" /> </td> <td class="small" width="122"> <p> <span id="wmqeeuq" class="ast">未显C需?JavaScript 的文档选项</span> </p> </td> </tr> </noscript> </tbody> </form> </table> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- 03/20/06 updated by gretchen --> <br /> <table cellspacing="0" cellpadding="0" width="150" border="0"> <tbody> <tr> <td class="v14-header-2-small">最新推?/td> </tr> </tbody> </table> <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td class="no-padding" width="150"> <table cellspacing="0" cellpadding="0" width="143" border="0"> <tbody> <tr valign="top"> <td width="8"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /> </td> <td> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" /> </td> <td width="125"> <p> <a class="smallplainlink" > <font color="#5c81a7" size="2">Java 应用开发源动力 Q?下蝲免费软gQ快速启动开?/font> </a> </p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <br /> </td> </tr> </tbody> </table> <p>U别: 初</p> <p> <a > <font color="#996699">Elliotte Rusty Harold</font> </a>, 副教? Polytechnic University<br /></p> <p>2005 q?5 ?26 ?/p> <blockquote>Cobertura 是一U开源工P它通过基本的代码Qƈ观察在测试包q行时执行了哪些代码和没有执行哪些代码,来测量测试覆盖率。除了找出未试到的代码q发?bug 外,Cobertura q可以通过标记无用的、执行不到的代码来优化代码,q可以提?API 实际操作的内部信息。Elliotte Rusty Harold 与您分享如何利用代码覆盖率的最佛_跉|使用 Cobertura?/blockquote> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <p>管试先行~程Qtest-first programmingQ和单元试已不能算是新概念Q但试驱动的开发仍然是q去 10 q中最重要的编E创新。最好的一些编Eh员在q去半个世纪中一直在使用q些技术,不过Q只是在最q几q_q些技术才被广泛地视ؓ在时间及成本预算内开发健壮的无缺陯Y件的关键所在。但是,试驱动的开发不能超q测试所能达到的E度。测试改q了代码质量Q但q也只是针对实际试到的那部分代码而言的。您需要有一个工具告诉您E序的哪些部分没有测试到Q这样就可以针对q些部分~写试代码q找出更?bug?</p> <p>Mark Doliner ?Cobertura Q?i>cobertura</i> 在西班牙语是覆盖的意思)是完成这Q务的一个免?GPL 工具。Cobertura 通过用额外的语句记录在执行测试包Ӟ哪些行被试到、哪些行没有被测试到Q通过q种方式来度量字节码Q以便对试q行监视。然后它生成一?HTML 或?XML 格式的报告,指出代码中的哪些包、哪些类、哪些方法和哪些行没有测试到。可以针对这些特定的区域~写更多的测试代码,以发现所有隐藏的 bug?</p> <p> <a name="N10074"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">阅读 Cobertura 输出</font> </span> </a> </p> <p>我们首先查看生成?Cobertura 输出。图 1 昄了对 Jaxen 试包运?Cobertura 生成的报告(请参?<a ><font color="#996699">参考资?/font></a>Q。从该报告中Q可以看C很好Q在 <code>org.jaxen.expr.iter</code> 包中几乎?100%Q到极差Q在 <code>org.jaxen.dom.html</code> 中完全没有覆盖)的覆盖率l果?/p> <br /> <a name="N1008B"> <b>?1. Jaxen 的包U别覆盖率统计数?/b> </a> <br /> <img height="490" alt="" hspace="5" src="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/overview.jpg" width="676" vspace="5" border="0" /> <br /> <p>Cobertura 通过被测试的行数和被试的分支数来计覆盖率。第一ơ测试时Q两U测试方法之间的差别q不是很重要。Cobertura qؓc计^?McCabe 复杂度(请参?<a ><font color="#996699">参考资?/font></a>Q?/p> <p>可以深入挖掘 HTML 报告Q了解特定包或者类的覆盖率。图 2 昄?<code>org.jaxen.function</code> 包的覆盖率统计。在q个包中Q覆盖率的范围从 <code>SumFunction</code> cȝ 100% ?<code>IdFunction</code> cȝ仅ؓ 5%?/p> <br /> <a name="N100B5"> <b>?2. org.jaxen.function 包中的代码覆盖率</b> </a> <br /> <img height="490" alt="" hspace="5" src="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/package.jpg" width="676" vspace="5" border="0" /> <br /> <p>q一步深入到单独的类中,具体查看哪一行代码没有测试到。图 3 昄?<code>NameFunction</code> cM的部分覆盖率。最左边一栏显C受后一栏显CZ执行试时这一行被执行的次数。可以看出,W?112 行被执行?100 ơ,W?114 行被执行?28 ơ。用U色H出昄的那些行则根本没有测试到。这个报告表明,虽然从M上说该方法被试CQ但实际上还有许多分支没有测试到?</p> <br /> <a name="N100D0"> <b>?3. NameFunction cM的代码覆盖率</b> </a> <br /> <img height="590" alt="" hspace="5" src="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/class.jpg" width="676" vspace="5" border="0" /> <br /> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"> <p>Cobertura ?jcoverage 的分支(请参?<a ><font color="#996699">参考资?/font></a>Q。GPL 版本?jcoverage 已经有一q没有更新过了,q且有一些长期存在的 bugQCobertura 修复了这?bug。原来的那些 jcoverage 开发h员不再l开发开放源码,他们转向开?jcoverage 的商业版?jcoverage+Qjcoverage+ 是一个从同一代码基础中发展出来的闭源代码品。开放源码的奇妙之处在于Q一个品不会因为原开发h员决定让他们的工作获得相应的报酬而消亡?</p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p> <a name="N100EC"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">认遗漏的测?/font> </strong> </span> </a> </p> <p>利用 Cobertura 报告Q可以找Z码中未测试的部分q对它们编写测试。例如,?3 昄 Jaxen 需要进行一些测试,q用 <code>name()</code> 函数Ҏ字节炏V注释节炏V处理指令节炏V属性节点和名称I间节点q行试?</p> <p>如果有许多未覆盖的代码,?Cobertura 在这里报告的那样Q那么添加所有缺的试会非常耗时Q但也是值得的。不一定要一ơ完成它。您可以从被试的最的代码开始,比如那些所有没有覆盖的包。在试所有的包之后,可以对每一个显CZؓ没有覆盖的类~写一些测试代码。对所有类q行专门试后,q要为所有未覆盖的方法编写测试代码。在试所有方法之后,可以开始分析对未测试的语句q行试的必要性?</p> <p> <a name="N100FC"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">Q几乎)不留下Q何未试的代?/font> </strong> </span> </a> </p> <p>是否有一些可以测试但不应试的内容?q取决于您问的是谁。在 JUnit FAQ 中,J. B. Rainsberger 写到“一般的看法是:如果 <i>自n</i> 不会出问题,那么它会因ؓ太简单而不会出问题。第一个例子是 <code>getX()</code> Ҏ。假?<code>getX()</code> Ҏ只提供某一实例变量的倹{在q种情况下,除非~译器或者解释器Z问题Q否?<code>getX()</code> 是不会出问题的。因此,不用试 <code>getX()</code>Q测试它不会带来M好处。对?<code>setX()</code> Ҏ来说也是如此Q不q,如果 <code>setX()</code> Ҏ实要进行Q何参数验证,或者说实有副作用Q那么还是有必要对其q行试。?</p> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"> <p>理论上,Ҏ覆盖的代码编写测试代码不一定就会发?bug。但在实践中Q我从来没有到没有发现 bug 的情c未试的代码充满了 bug。所做的试少Q在代码中隐藏的、未发现?bug ׃多?/p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p>我不同意。我已经C清在“简单得不会出问题”的代码中发现的 bug 的数量了。确实,一?getter ?setter 很简单,不可能出问题。但是我从来没有办法区分哪些方法是真的单得不会出错Q哪些方法只是看上去如此。编写覆盖像 setter ?getter q样单方法的试代码q不难。ؓ此所q量旉会因为在q些Ҏ中发现未N料到?bug 而得到补ѝ?</p> <p>一般来_开始测量后Q达?90% 的测试覆盖率是很Ҏ的。将覆盖率提高到 95% 或者更高就需要动一下脑{。例如,可能需要装载不同版本的支持库,以测试没有在所有版本的库中出现?bug。或者需要重新构Z码,以便试通常执行不到的部分代码。可以对c进行扩展,让它们的受保护方法变为公共方法,q样可以对q些Ҏq行试。这些技巧看h像是多此一举,但是它们曑ָ助我在一半的旉内发现更多的未发现的 bug?</p> <p>q不L可以得到完美的?00% 的代码覆盖率。有时您会发玎ͼ不管对代码如何改造,仍然有一些行、方法、甚x整个cL试不到的。下面是您可能会遇到的挑战的一些例子: </p> <ul> <li>只在特定q_上执行的代码。例如,在一个设计良好的 GUI 应用E序中,d一?Exit 菜单的代码可以?Windows PC 上运行,但它不能?Mac Zq行?br /><br /></li> <li>捕获不会发生的异常的 <code>catch</code> 语句Q比如在?<code>ByteArrayInputStream</code> q行d操作时抛出的 <code>IOException</code>?br /><br /></li> <li>非公q中的一些方法,它们永远也不会被实际调用Q只是ؓ了满x个接口契U而必d现?br /><br /></li> <li>处理虚拟?bug 的代码块Q比如说Q不能识?UTF-8 ~码?<br /><br /></li> </ul> <p>考虑C面这些以及类似的情况Q我认ؓ一些极限程序员自动删除所有未试代码的做法是不切实际的,q且可能h一定的讽刺性。不能L获得l对完美的测试覆盖率q不意味着׃会有更好的覆盖率?</p> <p>然而,比执行不到的语句和方法更常见的是D留代码Q它不再有Q何作用,q且从代码基中去掉这些代码也不会产生M影响。有时可以通过使用反射来访问私有成员这L怪招来测试未试的代码。还可以为未试的、包保护Qpackage-protectedQ的代码来编写测试代码,测试类攑ֈ要试的类所在那个包中。但最好不要这样做。所有不能通过发布的(公共的和受保护的Q接口访问的代码都应删除。执行不到的代码不应当成Z码基的一部分。代码基小Q它pҎ被理解和l护?</p> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"> <p>不要漏掉量单元试包和cLw。我不止一ơ注意到Q某些个试Ҏ或者类没有被测试包真正q行。通常q表明名U规范中存在问题Q比如将一个方法命名ؓ <code><i>tes</i>SomeReallyComplexCondition</code>Q而不是将其命名ؓ <code><i>test</i>SomeReallyComplexCondition</code>Q,或者忘记将一个类dC <code>suite()</code> Ҏ中。在其他情况下,未预期的条gD跌了测试方法中的代码。不是什么情况,都是虽然已经~写了测试代码,但没有真正运行它。JUnit 不会告诉您它没有像您所想的那样q行所有测试,但是 Cobertura 会告诉您。找Z未运行的试后,Ҏ它一般很Ҏ?</p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N10178"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">q行 Cobertura</font> </span> </a> </p> <p>在了解了量代码覆盖率的好处后,让我们再来讨Z下如何用 Cobertura 量代码覆盖率的具体l节。Cobertura 被设计成为在 Ant 中运行。现在还没有q方面的 IDE 插g可用Q不q一两年内也许就会有了?</p> <p>首先需要在 build.xml 文g中添加一个Q务定义。以下这个顶U?<code>taskdef</code> 元素?cobertura.jar 文g限定在当前工作目录中Q?</p> <table cellspacing="0" cellpadding="5" width="65%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"><taskdef classpath="cobertura.jar" resource="tasks.properties" /></font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>然后Q需要一?<code>cobertura-instrument</code> dQ该d在已经~译好的cL件中d日志代码?code>todir</code> 属性指定将量cLC么地斏V?code>fileset</code> 子元素指定测量哪?.class 文gQ?</p> <table cellspacing="0" cellpadding="5" width="65%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"><target name="instrument"> <cobertura-instrument todir="target/instrumented-classes"> <fileset dir="target/classes"> <include name="**/*.class"/> </fileset> </cobertura-instrument> </target></font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>用通常q行试包的同一U类型的 Ant dq行试。惟一的区别在于:被测量的cdd原始cd现在c\径中之前出现在类路径中,而且需要将 Cobertura JAR 文gd到类路径中: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"><target name="cover-test" depends="instrument"> <mkdir dir="${testreportdir}" /> <junit dir="./" failureproperty="test.failure" printSummary="yes" fork="true" haltonerror="true"> <!-- Normally you can create this task by copying your existing JUnit target, changing its name, and adding these next two lines. You may need to change the locations to point to wherever you've put the cobertura.jar file and the instrumented classes. --> <classpath location="cobertura.jar"/> <classpath location="target/instrumented-classes"/> <classpath> <fileset dir="${libdir}"> <include name="*.jar" /> </fileset> <pathelement path="${testclassesdir}" /> <pathelement path="${classesdir}" /> </classpath> <batchtest todir="${testreportdir}"> <fileset dir="src/java/test"> <include name="**/*Test.java" /> <include name="org/jaxen/javabean/*Test.java" /> </fileset> </batchtest> </junit> </target>></font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Jaxen 目使用 JUnit 作ؓ其测试框Ӟ但是 Cobertura 是不受框架媄响的。它?TestNG、Artima SuiteRunner、HTTPUni 或者在您自己在C室开发的pȝ中一样工作得很好?/p> <p>最后,<code>cobertura-report</code> d生成本文开始部分看到的那个 HTML 文gQ?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"><target name="coverage-report" depends="cover-test"> <cobertura-report srcdir="src/java/main" destdir="cobertura"/> </target></font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p> <code>srcdir</code> 属性指定原始的 .java 源代码在什么地斏V?code>destdir</code> 属性指?Cobertura 攄输出 HTML 的那个目录的名称?/p> <p>在自q Ant ~译文g中加入了cM的Q务后Q就可以通过键入以下命o来生成一个覆盖报告: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">% ant instrument % ant cover-test % ant coverage-report</font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>当然Q如果您愿意的话Q还可以改变目标d的名Uͼ或者将q三Q务合qؓ一个目标Q务?</p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N101CE"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">l束?/font> </span> </a> </p> <p>Cobertura 是敏L序员工具׃新增的一个重要工兗通过生成代码覆盖率的具体数|Cobertura 单元测试从一U艺术{变ؓ一门科学。它可以L试覆盖中的I隙Q直接找?bug。测量代码覆盖率使您可以获得Lq修?bug 所需的信息,从而开发出Ҏ个h来说都更健壮的Y件?</p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="resources"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">参考资?</font> </span> </a> </p> <ul> <li>您可以参阅本文在 developerWorks 全球站点上的 <a target="_blank"><font color="#5c81a7">英文原文</font></a>?br /><br /></li> <li>?SourceForge 下蝲 <a ><font color="#996699">Cobertura</font></a>?br /><br /></li> <li>获得 <a ><font color="#5c81a7">JUnit</font></a><a ><font color="#5c81a7">受媄响的试</font></a>Q它是用?Java q_的实际标准单元测试框架?br /><br /></li> <li>阅读 Dave Thomas ?Andy Hunt 合著?<a ><font color="#5c81a7"><i>Pragmatic Unit Testing in Java With JUnit</i></font></a>QPragmatic BookshelfQ?003Q?br /><br /></li> <li>Cenqua ?<a ><font color="#5c81a7">Clover</font></a> 是一个更_致的、收费的试覆盖率工P它所做的工作实质上与 Cobertura 相同Q只是它做得更细致一些?br /><br /></li> <li>IBM Rational 提供了全面的试工具包来帮助您检代码。?a ><font color="#5c81a7">Get started with automated testing: Road map to success</font></a>”ؓ您提供了卛_开始测试自q代码所需的基知识?<br /><br /></li> <li>Mike Kelly 提供了?a ><font color="#5c81a7">using TestManager to report test coverage</font></a>”的l节QdeveloperWorksQ?003 q?12 月)?br /><br /></li> <li> <a > <font color="#5c81a7">PureCoverage</font> </a> ?IBM Rational PurifyPlus 试工具包的一部分Q它是一个出色的代码覆盖率工兗Rational Application Developor 包括 PureCoverage 功能Q从?a ><font color="#5c81a7">使用 IBM Rational Application Developer for WebSphere Software q行lg试</font></a>”中可以了解关于它的更多知识QdeveloperWorksQ?005 q?3 月)?br /><br /></li> <li>Cobertura ?<a ><font color="#5c81a7">jcoverage</font></a> 的分支?<br /><br /></li> <li>Carnegie Mellon ?Software Engineering Institute 发表了对 <a ><font color="#996699">McCabe's Cyclomatic Complexity</font></a> 的详l说明?br /><br /></li> <li>David Carew ?Sandeep Desai 合著??a ><font color="#5c81a7">Keeping critters out of your code: How to use WebSphere and JUnit to prevent programming bugs</font></a>”(developerWorksQ?003 q?6 月) 分析了如何用 XP Ҏq行试?br /><br /></li> <li>Dennis M. Sosnoski <a ><font color="#5c81a7">推出</font></a> ?<a ><font color="#5c81a7">Classworking 工具?/font></a> pdQ探讨开源的 <a ><font color="#5c81a7">Hansel</font></a> ?<a ><font color="#5c81a7">Gretel</font></a> 代码覆盖率工兗?br /><br /></li> <li>参阅?a ><font color="#5c81a7">Test your tests with Jester</font></a>”,了解关于开放源代码 JUnit 试试器的知识?br /><br /></li> <li>Malcolm Davis 撰写的?a ><font color="#5c81a7">利用 Ant ?JUnit q行增量开?/font></a>”(developerWorksQ?000 q?11 月)介绍了如何将 JUnit 集成到自q目中?br /><br /></li> <li>Eric Allen ?Roy Miller 在他们各自的专栏 <a ><font color="#5c81a7">诊断 Java 代码</font></a> ?<a ><font color="#5c81a7">Demystifying Extreme Programming</font></a> 中经常讨论到单元试?br /><br /></li> <li>Erik Hatcher ?<a ><font color="#5c81a7">让编译和试q程自动?/font></a> QdeveloperWorksQ?001 q?8 月)展示了如何将增量试和连l编译结合到一个自动过E中?br /><br /></li> <li>探烦 <a ><font color="#5c81a7">FoCuS</font></a>Q这?IBM alphaWorks 的一个工P它实C功能覆盖ҎQƈ通过提供未测试区域的详细覆盖率信息来改进应用E序试?br /><br /></li> <li>作ؓ本文分析对象?<a ><font color="#5c81a7">Jaxen 目</font></a> 是一个用?Java ~程的开?XPath 引擎Q适合多种不同对象模型?<br /><br /></li> <li>?developerWorks ?<a ><font color="#5c81a7">Java 技术专?/font></a> 中可以找到关?Java ~程的各个方面的文章?br /><br /></li> <li>请参?<a ><font color="#5c81a7">Developer Bookstore</font></a>Q以获得一些技术书c的完整清单Q其中包括数百本 <a ><font color="#5c81a7">Java 相关主题</font></a> 的书c?br /></li> </ul> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="author"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">关于作?/font> </span> </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td colspan="3"> <font face="Arial" size="4"> <img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> </font> </td> </tr> <tr valign="top" align="left"> <td> <p> <font face="Arial" size="4"> </font> </p> </td> <td> <font face="Arial" size="4"> <img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /> </font> </td> <td width="100%"> <p>Elliotte Rusty Harold 出生在新奥尔良,现在他还定期回老家喝一美味的U葵汤。不q目前,他和d Beth 定居在纽U͘q布鲁克林的 Prospect HeightsQ同住的q有他的猫咪 CharmQ取自夸克)?MarjorieQ取自他x的名字)。他?Polytechnic 大学计算机科学的副教授,讲授 Java 技术和面向对象~程。他?<a ><font color="#5c81a7">Cafe au Lait</font></a> |站?Internet 上最受欢q的独立 Java 站点之一Q姊妹站?<a ><font color="#5c81a7">Cafe con Leche</font></a> 已经成ؓ最受欢q的 XML 站点之一。他的著作包?<a ><font color="#5c81a7"><i>Effective XML</i></font></a>?a ><font color="#5c81a7"><i>Processing XML with Java</i></font></a>?a ><font color="#5c81a7"><i>Java Network Programming</i></font></a>?<a ><font color="#5c81a7"><i>The XML 1.1 Bible</i></font></a>。目前他正在从事 XML ?<a ><font color="#5c81a7">XOM</font></a> API?a ><font color="#5c81a7">Jaxen</font></a> XPath 引擎?<a ><font color="#5c81a7">Jester</font></a> 试覆盖率工L开发工作?</p> </td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/supsky/aggbug/58967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/supsky/" target="_blank">eddy liao</a> 2006-07-19 12:52 <a href="http://www.aygfsteel.com/supsky/archive/2006/07/19/58967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q{_不要被覆盖报告所qhhttp://www.aygfsteel.com/supsky/archive/2006/07/19/58965.htmleddy liaoeddy liaoWed, 19 Jul 2006 04:48:00 GMThttp://www.aygfsteel.com/supsky/archive/2006/07/19/58965.htmlhttp://www.aygfsteel.com/supsky/comments/58965.htmlhttp://www.aygfsteel.com/supsky/archive/2006/07/19/58965.html#Feedback0http://www.aygfsteel.com/supsky/comments/commentRss/58965.htmlhttp://www.aygfsteel.com/supsky/services/trackbacks/58965.html

http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#N10149

q求代码质量: 不要被覆盖报告所qh

您是否曾被测试覆盖度量引入歧途?

developerWorks
文档选项
此作为电子邮件发? src=

此作为电子邮件发?/font>

未显C需?JavaScript 的文档选项

讨论


最新推?/td>

Java 应用开发源动力 Q?下蝲免费软gQ快速启动开?/font>


U别: 初

Andrew Glover , CTO, Vanward Technologies

2006 q?2 ?06 ?/p>

试覆盖工具对单元测试具有重要的意义Q但是经常被误用。这个月QAndrew Glover 会在他的新系?—?q求代码质量 中向您介l值得参考的专家意见。第一部分深入Cl覆盖报告中数字的真实含义。然后他会提出您可以早q经常地利用覆盖来确保代码质量的三个Ҏ?/blockquote>

您还记得以前大多数开发h员是如何q求代码质量的吗。在那时Q有技巧地攄 main() Ҏ被视为灵zM适当的测试方法。经历了漫长的道路以后,现在自动试已经成ؓ高质量代码开发的基本保证Q对此我很感谢。但是这q不是我所要感谢的全部。Java?开发h员现在拥有很多通过代码度量、静态分析等Ҏ来度量代码质量的工具。我们甚臛_l设法将重构分类成一pd便利的模式!

要获得有关代码质量问题的{案Q您可以讉K?Andrew Glover L?Code Quality 论坛?

所有的q些新的工具使得保代码质量比以前简单得多,不过您还需要知道如何用它们。在q个pd中,我将重点阐述有关保证代码质量的一些有时看上去有点秘的东ѝ除了带您一L悉有关代码质量保证的众多工具和技术之外,我还ؓ您说明:

  • 定义q有效度量最影响质量的代码方面?
  • 讑֮质量保证目标q照此规划您的开发过E?
  • 定哪个代码质量工具和技术可以满x的需要?
  • 实现最佛_践(清除不好的)Qɼ保代码质量及早q经常地 成ؓ开发实践中L且有效的斚w?

在这个月Q我首先看?Java 开发h员中最行也是最Ҏ的质量保证工具包Q测试覆盖度量?/p>

谨防上当

q是一个晚上鏖战后的早晨,大家都站在饮水机边上。开发h员和理人员们了解到一些经q良好测试的cd以达到超q?90% 的覆盖率Q正在高兴地互换着 NFL 风格的点心。团队的集体信心I前高涨。从q处可以听到 “放d重构吧?的声韻Ig~陷已成为遥q的记忆Q响应性也已微不道。但是一个很的反对声在_

奛_们,先生们,不要被覆盖报告所愚弄?/p>

现在Q不要误解我的意思:q不是说使用试覆盖工具是愚蠢的。对单元试范例Q它是很重要的。不q更重要的是您如何理解所得到的信息。许多开发团队会在这儿犯W一个错?/p>

高覆盖率只是表示执行了很多的代码Qƈ不意味着q些代码?i>很好?/i> 执行。如果您x的是代码的质量,必ȝ地理解试覆盖工具能做什么,不能做什么。然后您才能知道如何使用q些工具去获取有用的信息。而不是像许多开发h员那P只是满于高覆盖率?/p>
试覆盖度量

试覆盖工具通常可以很容易地d到确定的单元试q程中,而且l果可靠。下载一个可用的工具Q对您的 Ant ?Maven 构徏脚本作一些小的改动,您和您的同事有了在饮水上谈论的一U新报告Q?i>试覆盖报告。当 foo ?bar q样的程序包令h惊奇地显C?i>?/i> 覆盖率时Q您可以得到不小的安慰。如果您怿臛_您的部分代码可以保证?“没?BUG?的,您会觉得很安心。但是这样做是一个错误?/p>

存在不同cd的覆盖度量,但是l大多数的工具会x行覆?/i>Q也叫做语句覆盖。此外,有些工具会报?i>分支覆盖。通过用一个测试工h行代码库q捕h个测试过E中与被 “触及?的代码对应的数据Q就可以获得试覆盖度量。然后这些数据被合成盖报告。在 Java 世界中,q个试工具通常?JUnit 以及名ؓ Cobertura、Emma ?Clover {的覆盖工具?/p>

行覆?/i>只是指出代码的哪些行被执行。如果一个方法有 10 行代码,其中?8 行在试中被执行Q那么这个方法的行覆盖率?80%。这个过E在M层次上也工作得很好:如果一个类?100 行代码,其中?45 行被触及Q那么这个类的行覆盖率就?45%。同P如果一个代码库包含 10000 个非注释性的代码行,在特定的试q行中有 3500 行被执行Q那么这D代码的行覆盖率是 35%?/p>

报告分支覆盖 的工兯囑ֺ量决{点Q比如包含逻辑 AND ?OR 的条件块Q的覆盖率。与行覆盖一P如果在特定方法中有两个分支,q且两个分支在测试中都被覆盖Q那么您可以说这个方法有 100% 的分支覆盖率?/p>

问题是,q些度量有什么用Q很明显Q很Ҏ获得所有这些信息,不过您需要知道如何用它们。一些例子可以阐明我的观炏V?/p>



回页?/font>


代码覆盖在活?/font>

我在清单 1 中创Z一个简单的cM具体表述cdơ的概念。一个给定的cd以有一q串的父c,例如 VectorQ它的父cL AbstractListQ?code>AbstractList 的父cd?AbstractCollectionQ?code>AbstractCollection 的父cd?ObjectQ?/p>
清单 1. 表现cdơ的c?/b>
												
														package com.vanward.adana.hierarchy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Hierarchy {
  private Collection classes;
  private Class baseClass;

  public Hierarchy() {
    super();
    this.classes = new ArrayList();
  }

  public void addClass(final Class clzz){
    this.classes.add(clzz);
  }
  /**
   * @return an array of class names as Strings
   */
  public String[] getHierarchyClassNames(){
    final String[] names = new String[this.classes.size()];        
    int x = 0;
    for(Iterator iter = this.classes.iterator(); iter.hasNext();){
       Class clzz = (Class)iter.next();
       names[x++] = clzz.getName();
    }        
    return names;
  }

  public Class getBaseClass() {
    return baseClass;
  }

  public void setBaseClass(final Class baseClass) {
    this.baseClass = baseClass;
  }
}

												
										

正如您看到的Q清?1 中的 Hierarchy cd有一?baseClass 实例以及它的父类的集合。清?2 中的 HierarchyBuilder 通过两个复制 buildHierarchy 的重载的 static Ҏ创徏?Hierarchy cR?/p>
清单 2. cdơ生成器
												
														package com.vanward.adana.hierarchy;

public class HierarchyBuilder {  

  private HierarchyBuilder() {
    super();		
  }

  public static Hierarchy buildHierarchy(final String clzzName) 
    throws ClassNotFoundException{
      final Class clzz = Class.forName(clzzName, false, 
          HierarchyBuilder.class.getClassLoader());        
      return buildHierarchy(clzz);
  }

  public static Hierarchy buildHierarchy(Class clzz){
    if(clzz == null){
      throw new RuntimeException("Class parameter can not be null");
    }

    final Hierarchy hier = new Hierarchy();
    hier.setBaseClass(clzz);

    final Class superclass = clzz.getSuperclass();

    if(superclass != 
      null && superclass.getName().equals("java.lang.Object")){
       return hier; 
    }else{      
       while((clzz.getSuperclass() != null) && 
          (!clzz.getSuperclass().getName().equals("java.lang.Object"))){
             clzz = clzz.getSuperclass();
             hier.addClass(clzz);
       }	        
       return hier;
    }
  }      
}

												
										





回页?/font>


现在是测试时_

有关试覆盖的文章怎么能缺测试案例呢Q在清单 3 中,我定义了一个简单的有三个测试案例的 JUnit 试c,它将试图执行 Hierarchy cd HierarchyBuilder c:


清单 3. 试 HierarchyBuilderQ?/b>
												
														package test.com.vanward.adana.hierarchy;

import com.vanward.adana.hierarchy.Hierarchy;
import com.vanward.adana.hierarchy.HierarchyBuilder;
import junit.framework.TestCase;

public class HierarchyBuilderTest extends TestCase {
  
  public void testBuildHierarchyValueNotNull() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyName() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.Assert", 
       "junit.framework.Assert", 
         hier.getHierarchyClassNames()[1]);      
  }

  public void testBuildHierarchyNameAgain() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.TestCase", 
       "junit.framework.TestCase", 
         hier.getHierarchyClassNames()[0]);      
  }
 
}

												
										

因ؓ我是一个狂热的试人员Q我自然希望q行一些覆盖测试。对?Java 开发h员可用的代码覆盖工具中,我比较喜Ƣ用 CoberturaQ因为它的报告很友好。而且QCorbertura 是开放源码项目,它派生出?JCoverage 目的前w?/p>



回页?/font>


Cobertura 的报?/font>

q行 Cobertura q样的工具和q行您的 JUnit 试一L单,只是有一个用专门逻辑在测试时查代码以报告覆盖率的中间步骤Q这都是通过工具?Ant d?Maven 的目标完成的Q?/p>

正如您在?1 中看到的Q?code>HierarchyBuilder 的覆盖报告说明部分代?i>没有 被执行。事实上QCobertura 认ؓ HierarchyBuilder 的行覆盖率ؓ 59%Q分支覆盖率?75%?/p>
?1. Cobertura 的报?/b>

q样看来Q我的第一ơ覆盖测试是p|的。首先,带有 String 参数?buildHierarchy() ҎҎ没有被测试。其ơ,另一?buildHierarchy() Ҏ中的两个条g都没有被执行。有的是,所要关注的正是W二个没有被执行?if 块?/p>

因ؓ我所需要做的只是增加一些测试案例,所以我q不担心q一炏V一旦我到达了所x的区域,我就可以很好地完成工作。注意我q儿的逻辑Q我使用试报告来了解什?i>没有 被测试。现在我已经可以选择使用q些数据来增强测试或者l工作。在本例中,我准备增强我的测试,因ؓ我还有一些重要的区域未覆盖?/p>

CoberturaQ第二轮

清单 4 是一个更新过?JUnit 试案例Q增加了一些附加测试案例,以试囑֮全执?HierarchyBuilderQ?


清单 4. 更新q的 JUnit 试案例
												
														package test.com.vanward.adana.hierarchy;

import com.vanward.adana.hierarchy.Hierarchy;
import com.vanward.adana.hierarchy.HierarchyBuilder;
import junit.framework.TestCase;

public class HierarchyBuilderTest extends TestCase {
  
  public void testBuildHierarchyValueNotNull() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyName() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.Assert", 
       "junit.framework.Assert", 
         hier.getHierarchyClassNames()[1]);      
  }

  public void testBuildHierarchyNameAgain() { zo       
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.TestCase", 
       "junit.framework.TestCase", 
         hier.getHierarchyClassNames()[0]);      
  }

  public void testBuildHierarchySize() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be 2", 2, hier.getHierarchyClassNames().length);
  }

  public void testBuildHierarchyStrNotNull() throws Exception{
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyStrName() throws Exception{        
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertEquals("should be junit.framework.Assert", 
      "junit.framework.Assert",
        hier.getHierarchyClassNames()[1]);
  }

  public void testBuildHierarchyStrNameAgain() throws Exception{
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertEquals("should be junit.framework.TestCase", 
      "junit.framework.TestCase",
        hier.getHierarchyClassNames()[0]);      
  }

  public void testBuildHierarchyStrSize() throws Exception{        
     Hierarchy hier = 
        HierarchyBuilder.
        buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
     assertEquals("should be 2", 2, hier.getHierarchyClassNames().length);        
  }

  public void testBuildHierarchyWithNull() {
     try{
       Class clzz = null;
       HierarchyBuilder.buildHierarchy(clzz);
       fail("RuntimeException not thrown");
     }catch(RuntimeException e){}
  }
}

												
										

当我使用新的试案例再次执行试覆盖q程Ӟ我得C如图 2 所C的更加完整的报告。现在,我覆盖了未测试的 buildHierarchy() ҎQ也处理了另一?buildHierarchy() Ҏ中的两个 if 块。然而,因ؓ HierarchyBuilder 的构造器?private cd的,所以我不能通过我的试cL试它Q我也不兛_Q。因此,我的行覆盖率仍然只有 88%?/p>
?2. 谁说没有W二ơ机?/b>

正如您看到的Q用一个代码覆盖工?i>可以 揭露重要的没有相应测试案例的代码。重要的事情是,在阅L告(特别 是覆盖率高的Q时需要小心,它们也许隐含危险的信息。让我们看看两个例子Q看看在高覆盖率后面隐藏着什么?/p>



回页?/font>


条g带来的麻?/font>

正如您已l知道的Q代码中的许多变量可能有多种状态;此外Q条件的存在使得执行有多条\径。在留意q些问题之后Q我在清单 5 中定义一个极其简单只有一个方法的c:


清单 5.您能看出下面的缺陷吗Q?
												
														package com.vanward.coverage.example01;

public class PathCoverage {

  public String pathExample(boolean condition){
    String value = null;
    if(condition){
      value = " " + condition + " ";
    }
    return value.trim();
  }
}

												
										

您是否发C清单 5 中有一个隐藏的~陷呢?如果没有Q不要担心,我会在清?6 中写一个测试案例来执行 pathExample() Ҏq确保它正确地工作:


清单 6. JUnit 来救_
												
														package test.com.vanward.coverage.example01;

import junit.framework.TestCase;
import com.vanward.coverage.example01.PathCoverage;

public class PathCoverageTest extends TestCase {

  public final void testPathExample() {
    PathCoverage clzzUnderTst = new PathCoverage();
    String value = clzzUnderTst.pathExample(true);
    assertEquals("should be true", "true", value);
  }
}

												
										

我的试案例正确q行Q我的神奇的代码覆盖报告Q如下面?3 所C)使我看上d个超U明星,试覆盖率达C 100%Q?/p>
?3. 覆盖率明?

我想现在应该到饮水机边上去说了,但是{等Q我不是怀疑代码中有什么缺陷呢Q认真检查清?5 会发玎ͼ如果 condition ?falseQ那么第 13 行确实会抛出 NullPointerException?i>YeeshQ这儿发生了什么?

q表明行覆盖的确不能很好地指C测试的有效性?/p>



回页?/font>


路径的恐?/font>

在清?7 中,我定义了另一个包?indirect 的简单例子,它仍然有不能容忍的缺陗请注意 branchIt() Ҏ?if 条g的后半部分。(HiddenObject cd在清?8 中定义。)


清单 7. q个代码_?/b>
												
														package com.vanward.coverage.example02;

import com.acme.someotherpackage.HiddenObject;

public class AnotherBranchCoverage {
   
  public void branchIt(int value){
    if((value > 100) || (HiddenObject.doWork() == 0)){
      this.dontDoIt();
    }else{
      this.doIt();
    }
  }                             

  private void dontDoIt(){
    //don't do something...
  }

  private void doIt(){
    //do something!
  }   
}

												
										

呀Q清?8 中的 HiddenObject ?i>有害?/i>。与清单 7 中一P调用 doWork() Ҏ会导?RuntimeExceptionQ?/p>
清单 8. 上半部分Q?
												
														package com.acme.someotherpackage.HiddenObject;

public class HiddenObject {

  public static int doWork(){
    //return 1;
    throw new RuntimeException("surprise!");
  }
}

												
										

但是我的可以通过一个良好的试捕获q个异常Q在清单 9 中,我编写了另一个好的测试,以图挽回我的明星光环Q?/p>
清单 9. 使用 JUnit 规避风险
												
														package test.com.vanward.coverage.example02;

import junit.framework.TestCase;
import com.vanward.coverage.example02.AnotherBranchCoverage;

public class AnotherBranchCoverageTest extends TestCase {
    
  public final void testBranchIt() {
    AnotherBranchCoverage clzzUnderTst = new AnotherBranchCoverage();
    clzzUnderTst.branchIt(101);
  }    
}

												
										

您对q个试案例有什么想法?您也怼写出更多的测试案例,但是误想一下清?7 中不定的条件有不止一个的~短操作会如何。设惛_果前半部分中的逻辑比简单的 int 比较更复杂,那么?/i> 需要写多少试案例才能满意Q?/p>

仅仅l我数字

现在Q对清单 7?? 的测试覆盖率的分析结果不再会使您感到惊讶。在?4 的报告中昄我达C 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是Q我执行了第 10 行!


?4.愚弄的报?/b>

从第一印象看,q让我骄傌Ӏ但是这个报告有什么误导吗Q只是粗略地看一看报告中的数字,会导致您怿代码是经q?i>良好试?/i>。基于这一点,您也怼认ؓ出现~陷的风险很低。这个报告ƈ不能帮助您确?or ~短操作的后半部分是一个定时炸弹!





回页?/font>


质量试

我不止一ơ地_您可以(而且应该Q用测试覆盖工具作为您的测试过E的一部分。但?i>不要被覆盖报告所愚弄。关于覆盖报告您需要了解的主要事情是,覆盖报告最好用来检查哪些代?i>没有l过 充分的测试。当您检查覆盖报告时Q找低的|q了解ؓ什么特定的代码没有l过充分的测试。知道这些以后,开发h员、管理h员以?QA 专业人员可以在真正需要的地方使用试覆盖工具。通常有下列三U情况:

  • 估计修改已有代码所需的时?
  • 评估代码质量
  • 评定功能试

现在我可以断定对试覆盖报告的一些用方法会您引入歧途,下面q些最佛_践可以得测试覆盖报告可以真正ؓ您所用?/p>

1. 估计修改已有代码所需的时?/font>

对一个开发团队而言Q针对代码编写测试案例自然可以增加集体的信心。与没有相应试案例的代码相比,l过试的代码更Ҏ重构、维护和增强。测试案例因为暗CZ代码在测试工作中?i>如何 工作的,所以还可以充当内行的文档。此外,如果被测试的代码发生改变Q测试案例通常也会作相应的改变Q这与诸如注释和 Javadoc q样的静态代码文档不同?/p>

在另一斚wQ没有经q相应测试的代码更难于理解和安全?/i> 修改。因此,知道代码有没有被试Qƈ看看实际的测试覆盖数|可以让开发h员和理人员更准地预知修改已有代码所需的时间?/p>

再次回到饮水上,可以更好地阐明我的观炏V?/p>

市场部的 LindaQ“我们想让系l在用户完成一W交易时?x 工作。这需要多长时间。我们的用户需要尽快实现这一功能。?

理人员 JeffQ“让我看看,q个代码?Joe 在几个月前编写的Q需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成q项工作。?

LindaQ“JoeQ他是谁Q?

JeffQ“哦QJoeQ因Z不知道自己在q什么,所以被我解雇了。?

情况g有点不妙Q不是吗Q尽如此,Jeff q是Q务分配给?MaryQMary 也认够在两天内完成工?—?切地说Q在看到代码之前Ҏq么认ؓ的?/p>

MaryQ“Joe 写这些代码时是不?i>睡着?/i>Q这是我所见过的最差的代码。我甚至不能认q是 Java 代码。除非推倒重来,要不我根本没法修攏V?

情况?“饮水机?团队不妙Q不是吗Q但是我们假设,如果在这个不q的事g的当初,Jeff ?Mary 拥有一份测试报告,那么情况会如何呢Q当 Linda 要求实现新功能时QJeff 做的W一件事是查以前生成的覆盖报告。注意到需要改动的软g包几乎没有被覆盖Q然后他׃?Mary 商量?/p>

JeffQ“Joe ~写的这个代码很差,l大多数没经q测试。您认ؓ要支?Linda 所说的功能需要多长时_?

MaryQ“这个代码很混ؕ。我甚至都不想看到它。ؓ什么不?Mark 来做呢??

JeffQ“因?Mark 不编写测试,刚被我解雇了。我需要您试q个代码q作一些改动。告诉我您需要多长时间。?

MaryQ“我臛_需要两天编写测试,然后我会重构q个代码Q增加新的功能。我xd需要四天吧。?

正如他们所说的Q知识的力量是强大的。开发h员可以在试图修改代码之前 使用覆盖报告来检查代码质量。同P理人员可以使用覆盖数据更好C计开发h员实际所需的时间?/p>

2. 评估代码质量

开发h员的试可以降低代码中存在缺L风险Q因此现在很多开发团队在新开发和更改代码的同旉要编写单元测试。然而正如前面所提到?Mark 一Pq不L在编码的同时q行单元试Q因而会D低质量代码的出现?/p>

监控覆盖报告可以帮助开发团队迅速找Z断增长的没有 相应试的代码。例如,在一周开始时q行覆盖报告Q显C项目中一个关键的软g包的覆盖率是 70%。如果几天后Q覆盖率下降C 60%Q那么您可以推断Q?/p>

  • 软g包的代码行增加了Q但是没有ؓC码编写相应的试Q或者是新增加的试不能有效地覆盖新代码Q?br />
  • 删除了测试案例?br />
  • 上述两种情况都发生了?

能够监控事情的发展,无疑是g好事。定期地查阅报告使得讑֮目标Q例如获得覆盖率、维护代码行的测试案例的比例{)q监控事情的发展变得更ؓҎ。如果您发现试没有如期~写Q您可以提前采取一些行动,例如对开发h员进行培训、指导或帮助。与其让用户 “在使用中?发现E序~陷Q这些缺h应该在几个月前通过单的试暴露出来Q,或者等到管理h员发现没有编写单元测试时再感到惊Ӟ和愤怒)Q还不如采取一些预防性的措施?/p>

使用覆盖报告来确保正的试是一伟大的实践。关键是要训l有素地完成q项工作。例如,使每晚生成ƈ查阅覆盖报告成ؓq箋累计 q程的一部分?/p>

3. 评定功能试

假设覆盖报告在指?i>没有l过 _试的代码部分方面非常有效,那么质量保证人员可以使用q些数据来评定与功能试有关的关注区域。让我们回到 “饮水机?团队来看?QA 的负责h Drew 是如何评?Joe 的代码的Q?/p>

Drew ?Jeff _“我们ؓ下一个版本编写了试案例Q我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。?

JeffQ“哦Q我们在q个领域有好些问题。如果我是一个赌徒的话,我会对这个功能区域给予特别的x。Mary 正在对这个应用程序做一些其他的修改 —?她在~写单元试斚w做得很好Q但是这个代码也太差了点。?

DrewQ“是的,我正在确定工作的资源和别,看上L没必要那么担心了Q我估计我们的团队会对股交易模块引赯够的x。?

知识再次昄了其强大的力量。与其他软g生命周期中的风险承担者(例如 QAQ配合,您可以利用覆盖报告所提供的信息来降低风险。在上面的场景中Q也?Jeff 可以?Drew 的团队提供一个早期的不包?Mary 的所有修改的版本。不q无论如何,Drew 的团队都应该x应用E序的股交易方面,与其他具有相应单元测试的代码相比Q这个地方似乎存在更大的~陷风险?/p>



回页?/font>


试有什么好?/font>

对单元测试范例而言Q测试覆盖度量工h一个有点奇怪的l成部分。对于一个已存在的有益的q程Q覆盖度量可以增加其深度和精度。然而,您应该仔l地阅读代码覆盖报告。单独的高覆盖率q不能确保代码的质量。对于减缺P代码的高覆盖q不是必要条Ӟ管高覆盖的代码的确更少 有缺陗?/p>

试覆盖度量的窍门是使用覆盖报告扑և未经 试的代码,分别在微观和宏观两个U别。通过从顶层开始分析您的代码库Q以及分析单个类的覆盖,可以促进深入的覆盖测试。一旦您能够l合q些原则Q您和您的组l就可以在真正需要的地方使用覆盖度量工具Q例如估计一个项目所需的时_持箋监控代码质量以及促进?QA 的协作?/p>



回页?/font>


参考资?

  • 参与论坛讨论 ?br />
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文?br />
  • ?a >?Cobertura 量试覆盖?/font>”(Elliotte Rusty HaroldQdeveloperWorksQ?005 q?5 月)Q找出存?bug 的未l测试的代码?br />
  • ?a >Classworking 工具? ?Hansel ?Gretel 覆盖代码”(Dennis SosnoskiQdeveloperWorksQ?005 q?2 月)Q如何完成您的单元测试?使用代码覆盖工具扑և{案Q?br />
  • ?a >?Jester Ҏ试进行测?/font>”(Elliotte Rusty HaroldQdeveloperWorksQ?005 q?5 月)QJester 擅长发现试套g的问题,对代码库的结构方面有独特的洞察力?br />
  • ?a >The business value of software quality”(Geoffrey BessinQThe Rational EdgeQ?004 q?6 月)Q描q?IBM Rational 有关提高代码质量的主张ƈ列D出用来保证质量的主要工具?br />
  • Java 技术专?/font> Q数癄有关 Java ~程各方面的文章?




回页?/font>


关于作?/font>

Andrew Glover ?Vanward Technologies 公司?CTOQ该公司位于华盛特区大都会地区Q公司的专业领域是自动测试框架的构造,自动试框架可以降低软g bug 数量Q减集成和试的时_提高整体的代码稳定性。他q是 Java Testing PatternsQWileyQ?004 q?9 月)的合著?/p>



eddy liao 2006-07-19 12:48 发表评论
]]> վ֩ģ壺 | | | | | | ͨ| ˳| | ͨ| | ƽ| ³ľ| ˼é| ǭ| ľ| | ɽʡ| Ƥ| | | | | ˫| | û| ¯| | | ɽ| | | Ҵ| | | Դ| | ij| ŷ| | ¡|