﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-It‘s my SCM life-随笔分类-软件质量</title><link>http://www.blogjava.net/supsky/category/13240.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:51:03 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:51:03 GMT</pubDate><ttl>60</ttl><item><title>在ant中集成checkstyle工具</title><link>http://www.blogjava.net/supsky/archive/2006/07/20/59212.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Thu, 20 Jul 2006 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/supsky/archive/2006/07/20/59212.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/59212.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/20/59212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/59212.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/59212.html</trackback:ping><description><![CDATA[
		<p>checkstyle 是一个帮助开发者按照某种习惯编写 java 代码的工具，他实现了代码检查的自动化，帮助人们从这种繁琐的工作中解放出来。 </p>
		<p>默认提供了对 sun 编程规范的支持，但是 checkstyle 是一个具有高可配置性的，你完全可以根据自己的要求来配置需要检查的内容。<br /><br />有以下这些东西<br />\lib\checkstyle-3.1\contrib\checkstyle-noframes.xsl<br />\lib\checkstyle-3.1\checkstyle-all-3.1.jar<br />\lib\checkstyle-3.1\sun_checks.xml                    <br /><br />在build.xml文件中添加<br />    &lt;patternset id="java.files.pattern" includes="**/*.java"/&gt;</p>
		<p>    &lt;target name="checkstyle" depends="prepare"           依赖prepare target<br />        description="Check code style for compliance with coding standards"&gt;<br />        &lt;property name="checkstyle.data.dir"<br />            location="${build.dir}/docs/checkstyle"/&gt;                 存放路径<br />        &lt;property name="checkstyle.data.file"<br />            location="${checkstyle.data.dir}/checkstyle.xml"/&gt;     xml文件<br />        &lt;property name="checkstyle.report.file"<br />            location="${checkstyle.data.dir}/checkstyle.html"/&gt;   html文件<br />        &lt;property name="checkstyle.xsl.file"<br />            location="${checkstyle.dir}/contrib/checkstyle-noframes.xsl"/&gt;   选用的样式表，checkstyle.dir为jar包的位置<br />        &lt;mkdir dir="${checkstyle.data.dir}"/&gt;<br />        &lt;taskdef resource="checkstyletask.properties" classpath="${checkstyle.jar}"/&gt;  引入jar文件<br />        &lt;checkstyle config="${checkstyle.dir}/sun_checks.xml"                      选用sun的规范，可以修改为自己的最佳实践<br />            failOnViolation="false" failureProperty="checkstyle.failure"&gt;<br />            &lt;fileset dir="src"&gt;                                                                   对src目录进行检查<br />                &lt;patternset refid="java.files.pattern"/&gt;<br />            &lt;/fileset&gt;<br />            &lt;fileset dir="test"&gt;                                                                  对test目录进行检查<br />                &lt;patternset refid="java.files.pattern"/&gt;<br />            &lt;/fileset&gt;<br />            &lt;!-- uncomment to print to console as well --&gt;<br />            &lt;!--formatter type="plain"/--&gt;<br />            &lt;formatter type="xml" toFile="${checkstyle.data.file}"/&gt;         生成xml文件<br />        &lt;/checkstyle&gt;<br />        &lt;xslt in="${checkstyle.data.file}" out="${checkstyle.report.file}"<br />            style="${checkstyle.xsl.file}"/&gt;                                        生成报告,其格式取决于checkstyle.xsl.file<br />    &lt;/target&gt;<br /><br />如图所示：图1列出了所有文件，图2列出了所以错误<br /><br /><img height="1024" alt="checkstyle1.JPG" src="http://www.blogjava.net/images/blogjava_net/supsky/checkstyle1.JPG" width="1280" border="0" /><br /><br /><br /><img height="1024" alt="checkstyle2.JPG" src="http://www.blogjava.net/images/blogjava_net/supsky/checkstyle2.JPG" width="1280" border="0" /><br /><br /><br /><br />下面解释了一些常见的输出结果，以供参考。  <br />序号            输出内容意义    <br />1  Type  is  missing  a  javadoc  commentClass    缺少类型说明    <br />2“{”  should  be  on  the  previous  line  “{”  应该位于前一行    <br />3Methos  is  missing  a  javadoc  comment方法前面缺少javadoc注释    <br />4Expected  @throws  tag  for  “Exception”在注释中希望有@throws的说明    <br />5“.”  Is  preceeded  with  whitespace  “.”  前面不能有空格    <br />6“.”  Is  followed  by  whitespace“.”  后面不能有空格    <br />7“=”  is  not  preceeded  with  whitespace“=”  前面缺少空格    <br />8“=”  is  not  followed  with  whitespace“=”  后面缺少空格    <br />9“}”  should  be  on  the  same  line“}”  应该与下条语句位于同一行    <br />10Unused  @param  tag  for  “unused”没有参数“unused”，不需注释    <br />11Variable  “CA”  missing  javadoc变量“CA”缺少javadoc注释    <br />12Line  longer  than  80characters行长度超过80    <br />13Line  contains  a  tab  character行含有”tab”  字符    <br />14Redundant  “Public”  modifier冗余的“public”  modifier    <br />15Final  modifier  out  of  order  with  the  JSL  suggestionFinal  modifier的顺序错误    <br />16Avoid  using  the  “.*”  form  of  importImport格式避免使用“.*”    <br />17Redundant  import  from  the  same  package从同一个包中Import内容    <br />18Unused  import-java.util.listImport进来的java.util.list没有被使用    <br />19Duplicate  import  to  line  13重复Import同一个内容    <br />20Import  from  illegal  package从非法包中  Import内容    <br />21“while”  construct  must  use  “{}”“while”  语句缺少“{}”    <br />22Variable  “sTest1”  must  be  private  and  have  accessor  method变量“sTest1”应该是private的，并且有调用它的方法    <br />23Variable  “ABC”  must  match  pattern  “^[a-z][a-zA-Z0-9]*$”变量“ABC”不符合命名规则“^[a-z][a-zA-Z0-9]*$”    <br />24“(”  is  followed  by  whitespace“(”  后面不能有空格  25“)”  is  proceeded  by  whitespace“)”  前面不能有空格<br />25 Line has trailing spaces  行的最后不能有空格<br /><br />根据sun_checks.xml文件的内容，可以到<a href="http://checkstyle.sourceforge.net/checks.html">http://checkstyle.sourceforge.net/checks.html</a>这里查看具体的配置，实现你们的最佳实践<br /><br /></p>
<img src ="http://www.blogjava.net/supsky/aggbug/59212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-20 15:51 <a href="http://www.blogjava.net/supsky/archive/2006/07/20/59212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转贴)用 Jester 对测试进行测试</title><link>http://www.blogjava.net/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.blogjava.net/supsky/archive/2006/07/19/59000.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/59000.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/19/59000.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/59000.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/59000.html</trackback:ping><description><![CDATA[
		<a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/">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">测试套件有缺陷，这不是玩笑</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 测试的测试器 Jester，擅长发现测试套件的问题，并提供对代码基本结构的深入观察。Elliotte Rusty Harold 介绍了 Jester 并展示如何使用它才能得到最佳结果。" 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="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//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="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td width="16">
																																						<img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td class="small" width="122">
																																						<p>
																																								<span class="ast">未显示需要 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" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#author">
						<font color="#996699">Elliotte Rusty Harold</font>
				</a>, 副教授, Polytechnic University<br /></p>
		<p>2005 年 6 月 02 日</p>
		<blockquote>全面的单元测试套件对健壮的程序是必不可少的。但是如何才能保证测试套件测试了应当测试的每件事呢？Ivan Moore 的 JUnit 测试的测试器 Jester，擅长发现测试套件的问题，并提供对代码基本结构的深入观察。Elliotte Rusty Harold 介绍了 Jester 并展示如何使用它才能得到最佳结果。</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>测试先行的开发是极限编程（XP）中争议最少、采用最广泛的部分。到目前为止，大多数专业 Java 程序员都可能捕捉过测试 bug。（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#resources"><font color="#996699">参考资料</font></a> 获得有关“被测试传染”的更多信息。） JUnit 是 Java 社区事实上的标准测试框架，没有经过全面的 JUnit 测试套件测试过的系统是不完整的。如果您的项目有全面的测试套件，那么恭喜您：您将制作出质量良好的、有利于工作的软件。但是大多数代码基础相当复杂。您能确定每个方法都被测试到、每个分支都进入过么？如果不能，那么当这些方法和分支在生产中执行的时候，应用程序会如何表现呢？</p>
		<p>
				<a name="N10067">
						<span class="atitle">
								<font face="Arial" size="4">代码覆盖</font>
						</span>
				</a>
		</p>
		<p>对代码进行测试的下一步是用 <i>代码覆盖</i> 工具对测试进行度量。代码覆盖是一种查看一套测试覆盖了多少代码的方法。信心的获得，不仅需要知道测试了程序整体，还要知道每个方法在全部可能情况下都得到测试。传统情况下，这类度量的执行方法是在测试执行时对测试进行监视，可以通过 Java 虚拟机调试接口（JVMDI）或 Java 虚拟机工具接口 （JVMTI）进行，或者直接处理字节码。一次都没有执行过的语句是测试不到的。</p>
		<p>Clover 和 EMMA（参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#resources"><font color="#996699">参考资料</font></a>） 这类工具采用的这种方法对于发现测试不到的语句很有价值 —— 但是还不够。知道测试套件没有执行某个语句，可以证明该语句没测试到。但是，反过来不成立。如果执行了某一行代码，并不一定代表它得到测试。完全有可能存在这样的情况：测试并没有检查代码行是否生成正确结果。</p>
		<p>当然，没有人会编写测试套件对每个语句的结果都进行验证。在众多的问题当中，这个问题可能会破坏封装。您可能认为，针对特定输入，只有方法中的每一行都操作正确，方法才会生成预期结果。但是这个假设并不合理。例如，如果没有测试到所有可能输入，也就没有测试到为处理边际情况而设计的代码，这时会如何呢？有可能还会测试到每行代码，但有可能遗漏真正的 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>并不简单</b>
																		</a>
																		<br />
																		<p>Jester 的方法并不简单。这个工具有可能会报告大量假阳性。例如，它可能把 <code>System.out.println("Copyright 2005 Elliotte Rusty Harold")</code> 语句改成 <code>System.out.println("Copyright 3005 Elliotte Rusty Harold")</code> ，然后报告没有破坏发生。但是，假阳性一般很容易过滤出来。另外，通常也有合适的理由怀疑像这个示例一样的情况是否真的是假阳性。例如，对于版权日期 3005 是否是测试套件应当通知的 bug，有人可能会有异议。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10091">
						<span class="atitle">
								<font face="Arial" size="4">Jester 简介</font>
						</span>
				</a>
		</p>
		<p>这正是 Jester 发挥作用的地方。与 Clover 这类传统的代码覆盖工具不同，Jester 不去查看报告了哪行代码。相反，Jester 会修改源代码、重新编译源代码，然后运行测试套件，查看是否有什么事出错。例如，它会把 1 改成 2，或者把 <code>if (x &gt; y)</code> 改成 <code>if (false)</code>。如果测试套件的关注不够，没有注意到修改，那么就说明遗漏了某项测试。</p>
		<p>我将通过在开源的 Jaxen XPath 工具（参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#resources"><font color="#996699">参考资料</font></a>）上应用 Jester 而对它进行演示。Jaxen 有一个基于 JUnit 的测试套件，而且这个套件的代码覆盖并不完善。</p>
		<p>
				<a name="N100A9">
						<span class="smalltitle">
								<strong>
										<font face="Arial">入门</font>
								</strong>
						</span>
				</a>
		</p>
		<p>在运行 Jester 之前，所有对没有修改的源代码的单元测试都必须测试通过。如果不是这样，那么 Jester 就无法知道是不是它的修改造成了破坏。（为了演示，我不得不修复一个 bug，我过去为它编写了测试用例，但是没有跟踪修复它。） </p>
		<p>Jester 与 IDE 的集成不是特别好（或者根本不好），所以要让测试通过，重要的是正确设置 <code>CLASSPATH</code> 和目录。运行测试套件所需要的命令行对于每个项目都是不同的。因为 Jaxen 测试使用指向特定测试文件的相对 URL ，所以它的测试必须在 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 之前，还需要清楚针对测试套件的一项附加限制。除非测试失败，否则不能打印有关 <code>System.err</code> 的任何内容。Jester 要通过检查打印的内容来判断测试是否成功，所以对 <code>System.err</code> 的程序输出会把 Jester 弄混。</p>
		<p>测试套件运行无误之后，请做一份源代码树的拷贝。记住，Jester 要向代码故意加入 bug，所以您可不要冒险在出现问题的情况下遗漏一个 bug。（如果您在使用源代码控制，那么这不会是个大问题。如果没有，请暂停阅读本文，立即把代码签入 CVS 或 Subversion 仓库。）</p>
		<p>
				<a name="N100CC">
						<span class="smalltitle">
								<strong>
										<font face="Arial">运行 Jester</font>
								</strong>
						</span>
				</a>
		</p>
		<p>要运行 Jester，在路径中必须同时拥有 jester.jar 和 junit.jar（JUnit 没有和 Jester 绑在一起。需要分别下载）。Jester 在类路径中查找它的配置文件，所以必须还要把 Jester 的主目录放在类路径中。当然，还需要添加所测试的应用程序需要的其他 JAR。主类是 <code>jester.TestTester</code>。传递给这个程序的参数是测试应用程序的测试套件名称。（我不得不为 Jaxen 编写一个主类，因为它没有包含一个可以运行它的全部测试的类。）如果把全部必要的 JAR 文件和目录都添加到 <code>CLASSPATH</code> 环境变量，而不是把它们添加到 jre/lib/ext 或者用 <code>-classpath</code> 引用它们，那么 Jester 工作起来会更加稳定。下面是我针对 Jaxen 运行初始测试的方式：</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 运行很慢，即使检测一个文件也是如此。它显示一个进度对话框，如图 1 所示，并在 <code>System.out</code> 上打印输出，让您知道它在做的工作，并向您保证它并没有完全挂起。</p>
		<br />
		<a name="figure1">
				<b>图 1. Jester 进度</b>
		</a>
		<br />
		<img height="237" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-jester/jester.gif" width="600" />
		<br />
		<p>如果在第一次运行若干分钟（或者时间足够运行完整的测试套件，甚至更长）之后，什么输出也没有看到，那么 Jester 可能 <i>确实</i> 挂起了，这很可能是因为类路径的问题。如果每件事都进行顺利，那么应当看到像清单 1 所示的输出： </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 对类进行了 11 项修改，而只有一项造成测试失败。有些修改是假阳性，但是 11 处修改肯定不应当只报告 1 处。</p>
		<p>下一步是在不破坏测试套件的情况下查看 Jester 改变的代码，看看是否需要为它编写测试。Jester 在 GUI 中显示它进行的修改，如 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#figure1"><font color="#996699">图 1</font></a> 所示（它不能在无人控制的情况下运行，这有点烦人），在控制台上打印输出，如 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#listing1"><font color="#996699">清单 1</font></a> 所示，并生成 XML 文件，文件中是没有产生影响的修改列表，如清单 2 所示： </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">				&lt;JesterReport&gt;
&lt;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"&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7691" from="if (" to="if (true ||"/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7691" from="if (" to="if (false &amp;&amp;"/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7703" from="!=" to="=="/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7754" from="==" to="!="/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7757" from="1" to="2"/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7826" from="if (" to="if (true ||"/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="7826" from="if (" to="if (false &amp;&amp;"/&gt;
&lt;ChangeThatDidNotCauseTestsToFail index="24749" from="if (" to="if (false &amp;&amp;"/&gt;
&lt;/JestedFile&gt;&lt;/JesterReport&gt;</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Jester 的行号报告通常不是个好方法，所以最好是在控制台输出中查找修改的代码。下面是 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#listing1"><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>在这个方法中，这个修改是在类的结束处： </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>。所以下一步就是为这个方法编写一个测试。这个方法是 protected 的方法，所以测试不能直接调用它。有时需要编写一个子类（通常作为内部类）来测试 protected 的方法。但是在这个例子中，稍做一点检查就很快发现这个方法由同一个类中的两个 public 方法（<code>stringValue</code> 和 <code>numberValue</code>）直接调用。所以也可以用这两个方法来测试它：</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>最后一步是运行测试用例，确定它通过。下面是结果： </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 捕捉到一个 bug！方法没有像预期的那样工作。更有趣的是，对 bug 的调查揭示出潜在的设计缺陷。<code>BaseXPath</code> 类可能更适合作为抽象类而不是具体类。我发誓，我并不是特意挑选这个示例来公开这个 bug。我从 <code>BaseXPath</code> 开始只是因为它是顶级 org.jaxen 包的第一个类，而且我选择 <code>selectSingleNodeForContext</code> 作为所测试的方法也只是因为它是 Jester 报告的最后一个错误。我真的认为这个方法没有什么问题，但是我错了。如果某些事没有经过测试，那么就应当假设它是有问题的。Jester 会告诉您出了什么问题。</p>
		<p>下一步显而易见：修复 bug。（请确保同时对 Jester 正在处理的源树拷贝和实际树中的 bug 进行了修复。）然后，迭代 —— 针对这个类重新运行 Jester，直到任何修改都不能通过，或者可以通过的修改都是不相关的。在我为这个 bug 添加测试（并修复）之后，Jester 就报告 11 个修改中只有 8 个没有检测到，如 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#listing2"><font color="#996699">清单 2</font></a> 所示。这在调试中是经常出现的事：修复了一个问题就修复（或者暴露了）另外几个。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10172">
						<span class="atitle">
								<font face="Arial" size="4">Jester 的性能</font>
						</span>
				</a>
		</p>
		<p>因为 Jester 重新编译代码基，而且要为自己做的每个修改都重新运行测试套件，所以它的运行要比 Clover 这样的传统工具慢得多。因此，对性能加以关注是很重要的。可以用许多技术加快 Jester 的运行。 </p>
		<p>首先，如果编译在 Jester 执行时间中占了显著部分，那么请尝试使用一个更快的编译器。许多用户都报告采用 Jikes 代替 Javac 后速度有显著提高（参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#resources"><font color="#996699">参考资料</font></a>）。可以在 Jester 主目录中的 jester.cfg 文件中修改 Jester 使用的编译命令。</p>
		<p>第二，剖析和优化测试套件。一般情况下，人们对单元测试运行的速度没太注意，但是如果乘上 Jester 上千次执行测试套件的次数，那么任何节约都会非常显著。具体来说，要在测试套件中查找在正常代码中不会出现的问题。JUnit 会重新初始化每个执行方法的全部字段，所以如果不是测试类的每个方法都用的字段，那么把测试数据从字段中拿出来放在本地变量中，可以显著提高速度。如果形成的代码副本不合您的风格，请尝试把测试套件分成更小、更模块化的类，以便所有的初始数据可以在全部测试方法之间共享。</p>
		<p>第三，重新组织测试套件的 <code>suite</code> 方法，以便最脆弱的测试（修改之后最有可能出错的）在不太脆弱的测试之前运行。只要 Jester 发现一个测试失败，就会终止运行，所以尽早失败可以短路大量耗时的额外测试。</p>
		<p>第四，出于相似的原因，当测试失败的机会差不多时，把最快的测试放在第一位。按照大概的执行时间给测试排序。只在内存中执行的测试在访问磁盘的测试之前，访问磁盘的测试在访问 LAN 的测试之前，访问 LAN 的测试在访问 Internet 的测试之前。如果有些测试特别慢，试试去掉它们，即便这会增加假阳性的数量。在 XOM （一个用 Java 语言处理 XML 的 API）的测试套件中，在 50 个测试类中，只有很少的几个就占据了 90% 以上的执行时间。在测试的时候清除这些类可以带来 10 倍的性能提升。</p>
		<p>最后，也是最重要的，就是不要一次测试整个代码基。每次把测试限制在一个类上，而且只运行能够暴露这个类的覆盖不足的测试。可能需要更长时间来测试每个类，但是用这种方法，几乎可以立即填补不足、修复 bug，而不必为 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" href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10192">
						<span class="atitle">
								<font face="Arial" size="4">结束语</font>
						</span>
				</a>
		</p>
		<p>Jester 是聪明的程序员的工具包中一个重要的附加。它可以发现其他工具不能发现的代码覆盖不足，这会直接变成发现和修复 bug。使用 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" href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font face="Arial" size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-jester/" target="_blank"><font color="#5c81a7">英文原文</font></a>。<br /><br /></li>
				<li>从 SourceForge 下载 <a href="http://jester.sourceforge.net/"><font color="#5c81a7">Jester</font></a>。<br /><br /></li>
				<li>得到 <a href="http://junit.sourceforge.net/doc/testinfected/testing.htm"><font color="#5c81a7">test infected</font></a>。<br /><br /></li>
				<li>
						<a href="http://www.junit.org/">
								<font color="#5c81a7">JUnit</font>
						</a> 是 Java 代码事实上的标准单元测试框架，也是 Jester 依赖的框架。<br /><br /></li>
				<li>在本文中作为示例的 <a href="http://jaxen.codehaus.org/"><font color="#5c81a7">Jaxen</font></a> 项目是一个用于 Java 语言的开源 XPath 引擎，适用于许多不同的对象模型。<br /><br /></li>
				<li>
						<a href="http://www.cenqua.com/clover/">
								<font color="#5c81a7">Clover</font>
						</a> 是一个更传统的测试覆盖工具，是 Jester 的有益补充。它比 Jester 更容易使用，也快得多；但是它只能测试在测试期间执行的代码，而不是它真正要测试的代码。<br /><br /></li>
				<li>
						<a href="http://emma.sourceforge.net/">
								<font color="#5c81a7">EMMA</font>
						</a> 是一个免费、开源的代码覆盖工具。请学习面向 Java 程序员的各种不同的 <a href="http://www.opensourcetesting.org/unit_java.php"><font color="#5c81a7">开源单元测试工具</font></a> 和 <a href="http://java-source.net/open-source/code-coverage"><font color="#996699">开源代码覆盖工具</font></a> 的更多内容。<br /><br /></li>
				<li>请阅读 Dave Thomas 和 Andy Hunt 的 <a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0974514012"><font color="#5c81a7"><i>Pragmatic Unit Testing in Java With JUnit</i></font></a>（Pragmatic Bookshelf, 2003）。<br /><br /></li>
				<li>Dennis M. Sosnoski 通过介绍开源的 <a href="http://hansel.sourceforge.net/"><font color="#5c81a7">Hansel</font></a> 和 <a href="http://www.cs.uoregon.edu/research/perpetual/dasada/Software/Gretel/"><font color="#5c81a7">Gretel</font></a> 代码覆盖工具，<a href="http://www-128.ibm.com/developerworks/cn/java/j-cwt02095/"><font color="#5c81a7">开始</font></a> 了 <a href="http://www-128.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=Classworking+%E5%B7%A5%E5%85%B7%E7%AE%B1"><font color="#5c81a7">Classworking 工具箱</font></a> 系列。<br /><br /></li>
				<li>David Carew 和 Sandeep Desai 撰写的“<a href="http://www.ibm.com/developerworks/edu/i-dw-wes-junit-i.html?S_TACT=105AGX02"><font color="#5c81a7">Keeping critters out of your code: How to use WebSphere and JUnit to prevent programming bugs</font></a>”（developerWorks, 2003 年 6 月），介绍了采用 XP 方法进行测试。<br /><br /></li>
				<li>Malcolm Davis 撰写的“<a href="http://www-128.ibm.com/developerworks/cn/java/j-ant/"><font color="#5c81a7">利用 Ant 和 JUnit 进行增量开发</font></a>”（developerWorks，2000 年 11 月），解释了如何把 JUnit 集成到自己的项目中。<br /><br /></li>
				<li>Eric Allen 和 Roy Miller 在他们各自的专栏 <a href="http://www-128.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=%E8%AF%8A%E6%96%AD+Java+%E4%BB%A3%E7%A0%81"><font color="#5c81a7">诊断 Java 代码</font></a> 和 <a href="http://www.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=%E6%8F%AD%E5%BC%80%E6%9E%81%E7%AB%AF%E7%BC%96%E7%A8%8B%E7%9A%84%E7%A5%9E%E7%A7%98%E9%9D%A2%E7%BA%B1%EF%BC%9A"><font color="#5c81a7">揭开极端编程的神秘面纱</font></a> 中频繁地涉及到单元测试。<br /><br /></li>
				<li>Erik Hatcher 撰写的“<a href="http://www-128.ibm.com/developerworks/cn/java/j-junitmail/index.html"><font color="#5c81a7">让编译和测试过程自动化</font></a>”（developerWorks，2001 年 8 月），介绍了如何把增量测试和持续构建组合到一个自动的过程中。<br /><br /></li>
				<li>
						<a href="http://www.testdriven.com/">
								<font color="#5c81a7">Testdriven.com</font>
						</a> 是一个关于测试驱动开发的文章和资源的全面集合。<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/oss/jikes/">
								<font color="#5c81a7">Jikes</font>
						</a> 是一个用 C 编写的开源的 Java 编译器，运行起来比 javac 快得多。<br /><br /></li>
				<li>在 developerWorks <a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7">Java 技术专区</font></a> 可以找到 Java 编程各方面的文章。<br /><br /></li>
				<li>请访问 <a href="http://devworks.krcinfo.com/"><font color="#5c81a7">Developer Bookstore</font></a>，获得技术书籍的完整列表，其中包括数百本 <a href="http://devworks.krcinfo.com/WebForms/ProductList.aspx?Search=Category&amp;id=1200"><font color="#5c81a7">Java 相关主题</font></a> 的图书。<br /><br /></li>
				<li>通过参与 <a href="http://www.ibm.com/developerworks/blogs/"><font color="#5c81a7">developerWorks blogs</font></a> 加入 developerWorks 社区。<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" href="http://www-128.ibm.com/developerworks/cn/java/j-jester/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span 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 来自新奥尔良，现在他还定期返回新奥尔良研究一盆秋葵。但是，他和妻子 Beth 及他们的猫咪 Charm（以夸克命名）和 Marjorie（以他的岳母为名），定居在布鲁克林附近的 Prospect Heights。他是 Polytechnic 大学计算机科学的副教授，他在该校讲授 Java 和面向对象编程。他的 Web 站点 <a href="http://www.cafeaulait.org/"><font color="#5c81a7">Cafe au Lait</font></a> 已经成为 Internet 上最流行的独立 Java 站点之一，他的分站点 <a href="http://www.cafeconleche.org/"><font color="#5c81a7">Cafe con Leche</font></a> 已经成为最流行的 XML 站点之一。他的书包括 <a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0321150406"><font color="#5c81a7"><i>Effective XML</i></font></a>、<a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0201771861"><font color="#5c81a7"><i>Processing XML with Java</i></font></a>、<a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=1565928709"><font color="#5c81a7"><i>Java Network Programming</i></font></a>和 <a href="http://www.cafeconleche.org/books/bible3/"><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.blogjava.net/supsky/aggbug/59000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-19 15:33 <a href="http://www.blogjava.net/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 Java</title><link>http://www.blogjava.net/supsky/archive/2006/07/19/58999.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Wed, 19 Jul 2006 07:29:00 GMT</pubDate><guid>http://www.blogjava.net/supsky/archive/2006/07/19/58999.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/58999.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/19/58999.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/58999.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/58999.html</trackback:ping><description><![CDATA[
		<a href="http://java-source.net/open-source/code-coverage">http://java-source.net/open-source/code-coverage</a>
		<br />
		<br />
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/quilt">Quilt</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/quilt">Go To Quilt</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/emma">EMMA</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/emma">Go To EMMA</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/nounit">NoUnit</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/nounit">Go To NoUnit</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/insect">InsECT</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/insect">Go To InsECT</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/hansel">Hansel</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>Hansel is an extension to JUnit that adds code coverage testing to the testing framework.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/hansel">Go To Hansel</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jester">Jester</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jester">Go To Jester</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jvmdi-code-coverage-analyser">JVMDI Code Coverage Analyser</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jvmdi-code-coverage-analyser">Go To JVMDI Code Coverage Analyser</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/grobocodecoverage">GroboCodeCoverage</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/grobocodecoverage">Go To GroboCodeCoverage</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jcoverage-gpl">jcoverage/gpl</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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'.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jcoverage-gpl">Go To jcoverage/gpl</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jblanket">JBlanket</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>JBlanket is a tool for assessing and improving method coverage of unit test cases. It is integrated with JUnit and Ant.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/jblanket">Go To JBlanket</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/cobertura">Cobertura</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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.</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/cobertura">Go To Cobertura</a>
		</p>
		<h3>
				<span>
						<a class="projectlink" href="http://java-source.net/open-source/code-coverage/coverlipse">Coverlipse</a>
				</span>
		</h3>
		<table style="MARGIN-TOP: 5px; FONT-SIZE: 12px; MARGIN-LEFT: 5px" width="100%">
				<tbody>
						<tr>
								<td>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)</td>
								<!--
        
        -->
						</tr>
				</tbody>
		</table>
		<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 6px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<a class="projectlink" href="http://java-source.net/open-source/code-coverage/coverlipse">Go To Coverlipse</a>
		</p>
<img src ="http://www.blogjava.net/supsky/aggbug/58999.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-19 15:29 <a href="http://www.blogjava.net/supsky/archive/2006/07/19/58999.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转贴)追求代码质量: 监视圈复杂度</title><link>http://www.blogjava.net/supsky/archive/2006/07/19/58988.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Wed, 19 Jul 2006 07:06:00 GMT</pubDate><guid>http://www.blogjava.net/supsky/archive/2006/07/19/58988.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/58988.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/19/58988.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/58988.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/58988.html</trackback:ping><description><![CDATA[
		<a href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/">http://www-128.ibm.com/developerworks/cn/java/j-cq03316/</a>
		<br />
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<h1>
												<span style="COLOR: #999999">追求代码质量: </span>监视圈复杂度</h1>
										<p id="subtitle">当代码复杂度超出想像时该如何做</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="如果复杂度与缺陷紧密相关，那么监视代码库的复杂度值不是很有意义吗？Andrew Glover 将展示如何使用简单的代码度量工具和基于 Java 的工具来监视圈复杂度 (cyclomatic complexity)。" name="body" />
																														<input type="hidden" value="追求代码质量: 监视圈复杂度" 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="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//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 src="//www.ibm.com/i/c.gif" width="8" height="1" alt="" />
																																				</td>
																																				<td width="16">
																																						<img src="//www.ibm.com/i/c.gif" height="16" width="16" alt="" />
																																				</td>
																																				<td width="122" class="small">
																																						<p>
																																								<span class="ast">未显示需要 JavaScript 的文档选项</span>
																																						</p>
																																				</td>
																																		</tr>
																																</noscript>
																														</tbody>
																												</form>
																												<tr valign="top">
																														<td width="8">
																																<font color="#5c81a7" size="2">
																																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																</font>
																														</td>
																														<td width="16">
																																<font color="#5c81a7" size="2">
																																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" />
																																</font>
																														</td>
																														<td width="122">
																																<p>
																																		<a class="smallplainlink" href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
																																				<b>
																																						<font color="#996699" size="2">讨论</font>
																																				</b>
																																		</a>
																																</p>
																														</td>
																												</tr>
																										</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" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#author">
						<font color="#996699">Andrew Glover</font>
				</a>, 总裁, Stelligent Incorporated<br /></p>
		<p>2006 年 4 月 25 日</p>
		<blockquote>如果复杂度与缺陷紧密相关，那么监视代码库的复杂度值不是很有意义吗？Andrew Glover 将展示如何使用简单的代码度量工具和基于 Java™ 的工具来监视圈复杂度 (cyclomatic complexity)。</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>每位开发人员对代码质量的含义都有着自己的看法，并且大多数人对如何查找编写欠佳的代码也有自己的想法。甚至术语<i>代码味道（code smell）</i> 也已进入大众词汇表，成为描述代码需要改进的一种方式。</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="IDAHDQ1C">
																				<b>圈什么？</b>
																		</a>
																		<br />
																		<p>关于这篇文章和代码质量主题的任何其他文章的问题，请访问由 Andrew Glover 主持的 <a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10"><font color="#996699">Improve your Java Code Quality</font></a> 讨论论坛。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>代码味道通常由开发人员直接判定，有趣的是，它是许多代码注释综合在一起的味道。一些人声称公正的代码注释是好事情，而另一些人声称代码注释只是解释过于复杂的代码的一种机制。显然，Javadocs™ 很有用，但是多少内嵌注释才足以维护代码？如果代码已经编写得足够好，它还需要解释自己吗？</p>
		<p>这告诉我们，代码味道是一种评估代码的机制，它具有主观性。我相信，那些闻起来味道糟透了的代码可能是其他人曾经编写的最好的代码。以下这些短语听起来是不是很熟悉？ </p>
		<blockquote>
				<i>是的，它初看起来有点乱，但是您要看到它多么可扩展！！</i>
		</blockquote>
		<p>或者</p>
		<blockquote>
				<i>它让您感到迷惑，但显然您不了解它的模式。</i>
		</blockquote>
		<p>我们需要的是客观评估代码质量的方法，某种可以决定性地告诉我们正在查看的代码是否存在风险的东西。不管您是否相信，这种东西确实存在！用来客观评估代码质量的机制已经出现了一段时间了，只是大多数开发人员忽略了它们。这些机制被称为代码度量 (code metric)。</p>
		<p>
				<a name="IDA3DQ1C">
						<span class="atitle">
								<font face="Arial" size="4">代码度量的历史</font>
						</span>
				</a>
		</p>
		<p>几十年前，少数几个非常聪明的人开始研究代码，希望定义一个能够与缺陷关联的测量系统。这是一个非常有趣的主张：通过研究带 bug 代码中的模式，他们希望创建正式的模型，然后可以评估这些模型，在缺陷<i>成为缺陷之前</i> 捕获它们。</p>
		<p>在这条研究之路上，其他一些非常聪明的人也决定通过研究代码看看他们是否可以测量<i>开发人员的生产效率</i>。对每位开发人员的代码行的经典度量似乎只停留在表面上：</p>
		<blockquote>
				<i>Joe 生产的代码要比 Bill 多，因此 Joe 生产率更高一些，值得我们花钱聘请这样的人。此外，我注意到 Bill 经常在饮水机边闲晃，我认为我们应该解雇 Bill。</i>
		</blockquote>
		<p>但是这种生产率度量在实践中是非常令人失望的，主要是因为它容易被滥用。一些代码测量包括内嵌注释，并且这种度量实际上受益于剪切粘贴式开发 (cut-and-paste style development)。 </p>
		<blockquote>
				<i>Joe 编写了许多缺陷！其他每条缺陷也都是由他间接造成的。我们不该解雇 Bill，他的代码实际上是免检的。</i>
		</blockquote>
		<p>可以预见，生产率研究被证实是非常不准确的，但在管理团队 (management body) 广泛使用这种生产率度量以期了解每个人的能力的价值之前，情况并非如此。来自开发人员社区的痛苦反应是有理由的，对于一些人而言，那种痛苦感觉从未真正走远。</p>
		<p>
				<a name="IDAQEQ1C">
						<span class="smalltitle">
								<strong>
										<font face="Arial">未经雕琢的钻石</font>
								</strong>
						</span>
				</a>
		</p>
		<p>尽管存在这些失败，但在那些复杂度与缺陷的相互关系的研究中仍然有一些美玉。大多数开发人员忘记进行代码质量研究已有很长一段时间了，但对于那些仍正在钻研的人而言（特别是如果您也正在为追求代码质量而努力钻研），会在今天的应用中发现这些研究的价值。例如，您曾注意到一些长的方法有时难以理解吗？是否曾无法理解嵌套很深的条件从句中的逻辑？您的避开这类代码的本能是正确的。一些长的方法和带有大量路径的方法<i>是</i> 难以理解的，有趣的是，这类方法容易导致缺陷。 </p>
		<p>我将使用一些例子展示我要表达的意思。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDA0EQ1C">
						<span class="atitle">
								<font face="Arial" size="4">数字的海洋</font>
						</span>
				</a>
		</p>
		<p>研究显示，平均每人在其大脑中大约能够处理 7（±2）位数字。这就是为什么大多数人可以很容易地记住电话号码，但却很难记住大于 7 位数字的信用卡号码、发射次序和其他数字序列的原因。</p>
		<p>此原理还可以应用于代码的理解上。您以前大概已经看到过类似清单 1 中所示的代码片段：</p>
		<br />
		<a name="code1">
				<b>清单 1. 适用记忆数字的原理</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">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;
}

</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 1 展示了 9 条不同的路径。该代码片段实际上是一个 350 多行的方法的一部分，该方法展示了 41 条不同的路径。设想一下，如果您被分配一项任务，要修改此方法以添加一项新功能。如果您该方法不是您编写的，您认为您能只做必要的更改而不会引入任何缺陷吗？</p>
		<p>当然，您应该编写一个测试用例，但您会认为该测试用例能将您的特定更改在条件从句的海洋中隔离起来吗？ </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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDALFQ1C">
						<span class="atitle">
								<font face="Arial" size="4">测量路径复杂度</font>
						</span>
				</a>
		</p>
		<p>
				<i>圈复杂度</i> 是在我前面提到的那些研究期间开创的，它可以精确地测量路径复杂度。通过利用某一方法路由不同的路径，这一基于整数的度量可适当地描述方法复杂度。实际上，过去几年的各种研究已经确定：圈复杂度（或 CC）大于 10 的方法存在很大的出错风险。因为 CC 通过某一方法来表示路径，这是用来确定某一方法到达 100% 的覆盖率将需要多少测试用例的一个好方法。例如，以下代码（您可能记得本系列的第一篇文章中使用过它）包含一个逻辑缺陷： </p>
		<br />
		<a name="code2">
				<b>清单 2. PathCoverage 有一个缺陷！</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">public class PathCoverage {
  public String pathExample(boolean condition){
    String value = null;
    if(condition){
      value = " " + condition + " ";
    }
    return value.trim();
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>作为响应，我可以编写一个测试，它将达到 100% 的行覆盖率：</p>
		<br />
		<a name="code3">
				<b>清单 3. 一个测试产生完全覆盖！</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">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);
  }       
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>接下来，我将运行一个代码覆盖率工具，比如 Cobertura，并将获得如图 1 中所示的报告：</p>
		<br />
		<a name="IDAGGQ1C">
				<b>图 1. Cobertura 报告</b>
		</a>
		<br />
		<img height="399" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/coverage-ex01-i.jpg" width="515" border="0" />
		<br />
		<p>哦，有点失望。代码覆盖率报告指示 100% 的覆盖率，但我们知道这是一个误导。</p>
		<p>
				<a name="IDATGQ1C">
						<span class="smalltitle">
								<strong>
										<font face="Arial">二对二</font>
								</strong>
						</span>
				</a>
		</p>
		<p>注意，清单 2 中的 <code>pathExample()</code> 方法有一个值为 2 的 CC（一个用于默认路径，一个用于 <code>if</code> 路径）。使用 CC 作为更精确的覆盖率测量尺度意味着第二个测试用例是必需的。在这里，它将是不进入 <code>if</code> 条件语句而采用的路径，如清单 4 中的 <code>testPathExampleFalse()</code> 方法所示：</p>
		<br />
		<a name="code4">
				<b>清单 4. 沿着较少采用的路径向下</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">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);
  } 
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>正如您可以看到的，运行这个新测试用例会产生一个令人讨厌的 <code>NullPointerException</code>。在这里，有趣的是我们可以使用圈复杂度<i>而不是</i> 使用代码覆盖率来找出这个缺陷。代码覆盖率指示我们已经在一个测试用例之后完成了此操作，但 CC 却会强迫我们编写额外的测试用例。不算太坏，是吧？</p>
		<p>幸运的是，这里的测试中的方法有一个值为 2 的 CC。设想一下该缺陷被隐藏在 CC 为 102 的方法中的情况。祝您好运找到它！</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDA1HQ1C">
						<span class="atitle">
								<font face="Arial" size="4">图表上的 CC </font>
						</span>
				</a>
		</p>
		<p>Java 开发人员可使用一些开放源码工具来报告圈复杂度。其中一个这样的工具是 JavaNCSS，它通过检查 Java 源文件来确定方法和类的长度。此外，此工具还收集代码库中每个方法的圈复杂度。通过利用 Ant 任务或 Maven 插件配置 JavaNCSS，可以生成一个列出以下内容的 XML 报告：</p>
		<ul>
				<li>每个包中的类、方法、非注释代码行和各种注释样式的总数。<br /><br /></li>
				<li>每个类中非注释代码行、方法、内部类和 Javadoc 注释的总数。<br /><br /></li>
				<li>代码库中每个方法的非注释代码行的总数和圈复杂度。</li>
		</ul>
		<p>该工具附带了少量样式表，可以使用它们来生成总结数据的 HTML 报告。例如，图 2 阐述了 Maven 生成的报告：</p>
		<br />
		<a name="IDAQQ02C">
				<b>图 2. Maven 生成的 JavaNCSS 报告</b>
		</a>
		<br />
		<img height="281" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/javancss.jpg" width="572" border="0" />
		<br />
		<p>此报告中带有 <i>Top 30 functions containing the most NCSS</i> 标签的部分详细描述了代码库中最长的方法，顺便提一句，该方法<i>几乎总是</i> 与包含最大圈复杂度的方法相关联。例如，该报告列出了 <code>DBInsertQueue</code> 类的 <code>updatePCensus()</code> 方法，因为此方法的非注释行总数为 283，圈复杂度（标记为 CCN）为 114。</p>
		<p>正如上面所演示的，圈复杂度是代码复杂度的一个好的指示器；此外，它还是用于开发人员测试的一个极好的衡量器。一个好的经验法则是创建数量与将被测试代码的圈复杂度值相等的测试用例。在图 2 中所见的 <code>updatePCensus()</code> 方法中，将需要 114 个测试用例来达到完全覆盖。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAQR02C">
						<span class="atitle">
								<font face="Arial" size="4">分而治之</font>
						</span>
				</a>
		</p>
		<p>在面对指示高圈复杂度值的报告时，第一个行动是检验所有相应测试的存在。如果存在一些测试，测试的数量是多少？除了极少数代码库以外，几乎所有代码库实际上都有 114 个测试用例用于 <code>updatePCensus()</code> 方法（实际上，为一个方法编写如此多的测试用例可能会花费很长时间）。但即使是很小的一点进步，它也是减少方法中存在缺陷风险的一个伟大开始。</p>
		<p>如果没有任何相关的测试用例，显然需要测试该方法。您首先想到的可能是：到重构的时间了，但这样做将打破第一个重构规则，即将编写一个测试用例。先编写测试用例会降低重构中的风险。减少圈复杂度的最有效方式是隔离代码部分，将它们放入新的方法中。这会降低复杂度，使方法更容易管理（因此更容易测试）。当然，随后应该测试那些更小的方法。</p>
		<p>在持续集成环境中，<i>随时间变化</i> 评估方法的复杂度是有可能的。如果是第一次运行报告，那么您可以监视方法的复杂度值或任何相关的成长度（growth）。如果在 CC 中看到一个成长度，那么您可以采取适当的动作。</p>
		<p>如果某一方法的 CC 值在不断增长，那么您有两个响应选择：</p>
		<ul>
				<li>确保相关测试的健康情况仍然表现为减少风险。 
</li>
				<li>评估重构方法减少任何长期维护问题的可能性。</li>
		</ul>
		<p>还要注意的是，JavaNCSS 不是惟一用于 Java 平台促进复杂度报告的工具。PMD 是另一个分析 Java 源文件的开源项目，它有一系列的规则，其中之一就是报告圈复杂度。CheckStyle 是另一个具有类似的圈复杂度规则的开放源码项目。PMD 和 CheckStyle 都有 Ant 任务和 Maven 插件（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#resources"><font color="#996699">参考资料</font></a>，从那里获得关于至此为止讨论的所有工具的更多信息。）</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAKS02C">
						<span class="atitle">
								<font face="Arial" size="4">使用复杂度度量</font>
						</span>
				</a>
		</p>
		<p>因为圈复杂度是如此好的一个代码复杂度指示器，所以测试驱动的开发 (test-driven development) 和低 CC 值之间存在着紧密相关的联系。在编写测试时（注意，我没有暗示是<i>第一次</i>），开发人员通常倾向于编写不太复杂的代码，因为<i>复杂的代码难以测试</i>。如果您发现自己难以编写某一代码，那么这是一种警示，表示正在测试的代码可能很复杂。在这些情况下，TDD 的简短的 “代码、测试、代码、测试” 循环将导致重构，而这将继续驱使非复杂代码的开发。</p>
		<p>所以，在使用遗留代码库的情况下，测量圈复杂度特别有价值。此外，它有助于分布式开发团队监视 CC 值，甚至对具有各种技术级别的大型团队也是如此。确定代码库中类方法的 CC 并连续监视这些值将使您的团队<i>在复杂问题出现时</i> 抢先处理它们。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font face="Arial" size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<b>学习</b>
		<br />
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-cq03316/" target="_blank"><font color="#5c81a7">英文原文</font></a> 。 <br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/cn/java/j-cq01316/"><font color="#996699">追求代码质量: 不要被覆盖报告所迷惑</font></a>”（Andrew Glover，developerWorks，2006 年 1 月）：测试覆盖率的测量是否让您误入歧途？找出新系列中的第一篇文章！<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/cn/views/java/tutorials.jsp?cv_doc_id=88282"><font color="#5c81a7">测试优先 Ruby 编程</font></a>”（Pat Eyler，developerWorks，2005 年 5 月）：test-first 开发中的一个简单练习，其中包括关于重构的讨论。<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/cn/java/j-cobertura/"><font color="#996699">用 Cobertura 测量测试覆盖率</font></a>”（Elliotte Rusty Harold，developerWorks，2005 年 5 月）：关于使用 Cobertura 来测量测试覆盖率的初级读物。<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/java/">
								<font color="#5c81a7">Java 技术专区</font>
						</a>：数百篇 Java 编程各方面的文章。</li>
		</ul>
		<br />
		<b>获得产品和技术</b>
		<br />
		<ul>
				<li>
						<a href="http://www.kclee.de/clemens/java/javancss/">
								<font color="#5c81a7">JavaNCSS</font>
						</a>：适用于 Java 平台的一个源代码测量套件。<br /><br /></li>
				<li>
						<a href="http://pmd.sourceforge.net//">
								<font color="#5c81a7">PMD</font>
						</a>：这个流行的开放源码工具扫描 Java 代码以发现问题。<br /><br /></li>
				<li>
						<a href="http://checkstyle.sourceforge.net/">
								<font color="#5c81a7">CheckStyle</font>
						</a>：来自 SourceForge 的另一个 Java 分析工具。<br /><br /></li>
		</ul>
		<br />
		<b>讨论</b>
		<br />
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
								<font color="#996699">参与论坛讨论</font>
						</a>。<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/blogs/">
								<font color="#5c81a7">developerWorks blogs</font>
						</a>：加入 developerWorks 社区！<br /><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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq03316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span 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">
														<img height="80" alt="" src="http://www.ibm.com/developerworks/i/p-aglover.jpg" width="64" align="left" name="Andrew Glover" />
												</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>Andrew Glover 是 <a href="http://www.stelligent.com/"><font color="#5c81a7">Stelligent Incorporated</font></a> 的总裁，该公司采用有效的开发人员测试策略和持续集成技术（让团队能够尽早且经常地监视代码质量）帮助其他公司解决软件开发质量问题。他还是 <a href="http://www.wiley.com/WileyCDA/WileyTitle/productCd-047144846X,descCd-authorInfo.html"><font color="#5c81a7">Java Testing Patterns</font></a>（Wiley，2004 年 9 月）一书的合著者。 </p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/supsky/aggbug/58988.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-19 15:06 <a href="http://www.blogjava.net/supsky/archive/2006/07/19/58988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转贴）用 Cobertura 测量测试覆盖率</title><link>http://www.blogjava.net/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.blogjava.net/supsky/archive/2006/07/19/58967.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/58967.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/19/58967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/58967.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/58967.html</trackback:ping><description><![CDATA[
		<a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/">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 是一种开源工具，它通过检测基本的代码，并观察在测试包运行时执行了哪些代码和没有执行哪些代码，来测量测试覆盖率。除了找出未测试到的代码并发现 bug 外，Cobertura 还可以通过标记无用的、执行不到的代码来优化代码，还可以提供 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="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//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="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td width="16">
																																						<img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td class="small" width="122">
																																						<p>
																																								<span class="ast">未显示需要 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" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#author">
						<font color="#996699">Elliotte Rusty Harold</font>
				</a>, 副教授, Polytechnic University<br /></p>
		<p>2005 年 5 月 26 日</p>
		<blockquote>Cobertura 是一种开源工具，它通过检测基本的代码，并观察在测试包运行时执行了哪些代码和没有执行哪些代码，来测量测试覆盖率。除了找出未测试到的代码并发现 bug 外，Cobertura 还可以通过标记无用的、执行不到的代码来优化代码，还可以提供 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>尽管测试先行编程（test-first programming）和单元测试已不能算是新概念，但测试驱动的开发仍然是过去 10 年中最重要的编程创新。最好的一些编程人员在过去半个世纪中一直在使用这些技术，不过，只是在最近几年，这些技术才被广泛地视为在时间及成本预算内开发健壮的无缺陷软件的关键所在。但是，测试驱动的开发不能超过测试所能达到的程度。测试改进了代码质量，但这也只是针对实际测试到的那部分代码而言的。您需要有一个工具告诉您程序的哪些部分没有测试到，这样就可以针对这些部分编写测试代码并找出更多 bug。 </p>
		<p>Mark Doliner 的 Cobertura （<i>cobertura</i> 在西班牙语是覆盖的意思）是完成这项任务的一个免费 GPL 工具。Cobertura 通过用额外的语句记录在执行测试包时，哪些行被测试到、哪些行没有被测试到，通过这种方式来度量字节码，以便对测试进行监视。然后它生成一个 HTML 或者 XML 格式的报告，指出代码中的哪些包、哪些类、哪些方法和哪些行没有测试到。可以针对这些特定的区域编写更多的测试代码，以发现所有隐藏的 bug。 </p>
		<p>
				<a name="N10074">
						<span class="atitle">
								<font face="Arial" size="4">阅读 Cobertura 输出</font>
						</span>
				</a>
		</p>
		<p>我们首先查看生成的 Cobertura 输出。图 1 显示了对 Jaxen 测试包运行 Cobertura 生成的报告（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#resources"><font color="#996699">参考资料</font></a>）。从该报告中，可以看到从很好（在 <code>org.jaxen.expr.iter</code> 包中几乎是 100%）到极差（在 <code>org.jaxen.dom.html</code> 中完全没有覆盖）的覆盖率结果。</p>
		<br />
		<a name="N1008B">
				<b>图 1. Jaxen 的包级别覆盖率统计数据</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 通过被测试的行数和被测试的分支数来计算覆盖率。第一次测试时，两种测试方法之间的差别并不是很重要。Cobertura 还为类计算平均 McCabe 复杂度（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#resources"><font color="#996699">参考资料</font></a>）。</p>
		<p>可以深入挖掘 HTML 报告，了解特定包或者类的覆盖率。图 2 显示了 <code>org.jaxen.function</code> 包的覆盖率统计。在这个包中，覆盖率的范围从 <code>SumFunction</code> 类的 100% 到 <code>IdFunction</code> 类的仅为 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>进一步深入到单独的类中，具体查看哪一行代码没有测试到。图 3 显示了 <code>NameFunction</code> 类中的部分覆盖率。最左边一栏显示行号。后一栏显示了执行测试时这一行被执行的次数。可以看出，第 112 行被执行了 100 次，第 114 行被执行了 28 次。用红色突出显示的那些行则根本没有测试到。这个报告表明，虽然从总体上说该方法被测试到了，但实际上还有许多分支没有测试到。 </p>
		<br />
		<a name="N100D0">
				<b>图 3. NameFunction 类中的代码覆盖率</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 href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#resources"><font color="#996699">参考资料</font></a>）。GPL 版本的 jcoverage 已经有一年没有更新过了，并且有一些长期存在的 bug，Cobertura 修复了这些 bug。原来的那些 jcoverage 开发人员不再继续开发开放源码，他们转向开发 jcoverage 的商业版和 jcoverage+，jcoverage+ 是一个从同一代码基础中发展出来的封闭源代码产品。开放源码的奇妙之处在于：一个产品不会因为原开发人员决定让他们的工作获得相应的报酬而消亡。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N100EC">
						<span class="smalltitle">
								<strong>
										<font face="Arial">确认遗漏的测试</font>
								</strong>
						</span>
				</a>
		</p>
		<p>利用 Cobertura 报告，可以找出代码中未测试的部分并针对它们编写测试。例如，图 3 显示 Jaxen 需要进行一些测试，运用 <code>name()</code> 函数对文字节点、注释节点、处理指令节点、属性节点和名称空间节点进行测试。 </p>
		<p>如果有许多未覆盖的代码，像 Cobertura 在这里报告的那样，那么添加所有缺少的测试将会非常耗时，但也是值得的。不一定要一次完成它。您可以从被测试的最少的代码开始，比如那些所有没有覆盖的包。在测试所有的包之后，就可以对每一个显示为没有覆盖的类编写一些测试代码。对所有类进行专门测试后，还要为所有未覆盖的方法编写测试代码。在测试所有方法之后，就可以开始分析对未测试的语句进行测试的必要性。 </p>
		<p>
				<a name="N100FC">
						<span class="smalltitle">
								<strong>
										<font face="Arial">（几乎）不留下任何未测试的代码</font>
								</strong>
						</span>
				</a>
		</p>
		<p>是否有一些可以测试但不应测试的内容？这取决于您问的是谁。在 JUnit FAQ 中，J. B. Rainsberger 写到“一般的看法是：如果 <i>自身</i> 不会出问题，那么它会因为太简单而不会出问题。第一个例子是 <code>getX()</code> 方法。假定 <code>getX()</code> 方法只提供某一实例变量的值。在这种情况下，除非编译器或者解释器出了问题，否则 <code>getX()</code> 是不会出问题的。因此，不用测试 <code>getX()</code>，测试它不会带来任何好处。对于 <code>setX()</code> 方法来说也是如此，不过，如果 <code>setX()</code> 方法确实要进行任何参数验证，或者说确实有副作用，那么还是有必要对其进行测试。” </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。但在实践中，我从来没有碰到没有发现 bug 的情况。未测试的代码充满了 bug。所做的测试越少，在代码中隐藏的、未发现的 bug 就会越多。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>我不同意。我已经记不清在“简单得不会出问题”的代码中发现的 bug 的数量了。确实，一些 getter 和 setter 很简单，不可能出问题。但是我从来就没有办法区分哪些方法是真的简单得不会出错，哪些方法只是看上去如此。编写覆盖像 setter 和 getter 这样简单方法的测试代码并不难。为此所花的少量时间会因为在这些方法中发现未曾预料到的 bug 而得到补偿。 </p>
		<p>一般来说，开始测量后，达到 90% 的测试覆盖率是很容易的。将覆盖率提高到 95% 或者更高就需要动一下脑筋。例如，可能需要装载不同版本的支持库，以测试没有在所有版本的库中出现的 bug。或者需要重新构建代码，以便测试通常执行不到的部分代码。可以对类进行扩展，让它们的受保护方法变为公共方法，这样就可以对这些方法进行测试。这些技巧看起来像是多此一举，但是它们曾帮助我在一半的时间内发现更多的未发现的 bug。 </p>
		<p>并不总是可以得到完美的、100% 的代码覆盖率。有时您会发现，不管对代码如何改造，仍然有一些行、方法、甚至是整个类是测试不到的。下面是您可能会遇到的挑战的一些例子： </p>
		<ul>
				<li>只在特定平台上执行的代码。例如，在一个设计良好的 GUI 应用程序中，添加一个 Exit 菜单项的代码可以在 Windows PC 上运行，但它不能在 Mac 机上运行。<br /><br /></li>
				<li>捕获不会发生的异常的 <code>catch</code> 语句，比如在从 <code>ByteArrayInputStream</code> 进行读取操作时抛出的 <code>IOException</code>。<br /><br /></li>
				<li>非公共类中的一些方法，它们永远也不会被实际调用，只是为了满足某个接口契约而必须实现。<br /><br /></li>
				<li>处理虚拟机 bug 的代码块，比如说，不能识别 UTF-8 编码。 <br /><br /></li>
		</ul>
		<p>考虑到上面这些以及类似的情况，我认为一些极限程序员自动删除所有未测试代码的做法是不切实际的，并且可能具有一定的讽刺性。不能总是获得绝对完美的测试覆盖率并不意味着就不会有更好的覆盖率。 </p>
		<p>然而，比执行不到的语句和方法更常见的是残留代码，它不再有任何作用，并且从代码基中去掉这些代码也不会产生任何影响。有时可以通过使用反射来访问私有成员这样的怪招来测试未测试的代码。还可以为未测试的、包保护（package-protected）的代码来编写测试代码，将测试类放到将要测试的类所在那个包中。但最好不要这样做。所有不能通过发布的（公共的和受保护的）接口访问的代码都应删除。执行不到的代码不应当成为代码基的一部分。代码基越小，它就越容易被理解和维护。 </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>不要漏掉测量单元测试包和类本身。我不止一次注意到，某些个测试方法或者类没有被测试包真正运行。通常这表明名称规范中存在问题（比如将一个方法命名为 <code><i>tes</i>SomeReallyComplexCondition</code>，而不是将其命名为 <code><i>test</i>SomeReallyComplexCondition</code>），或者忘记将一个类添加到主 <code>suite()</code> 方法中。在其他情况下，未预期的条件导致跳过了测试方法中的代码。不管是什么情况，都是虽然已经编写了测试代码，但没有真正运行它。JUnit 不会告诉您它没有像您所想的那样运行所有测试，但是 Cobertura 会告诉您。找出了未运行的测试后，改正它一般很容易。 </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" href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10178">
						<span class="atitle">
								<font face="Arial" size="4">运行 Cobertura</font>
						</span>
				</a>
		</p>
		<p>在了解了测量代码覆盖率的好处后，让我们再来讨论一下如何用 Cobertura 测量代码覆盖率的具体细节。Cobertura 被设计成为在 Ant 中运行。现在还没有这方面的 IDE 插件可用，不过一两年内也许就会有了。 </p>
		<p>首先需要在 build.xml 文件中添加一个任务定义。以下这个顶级 <code>taskdef</code> 元素将 cobertura.jar 文件限定在当前工作目录中： </p>
		<table cellspacing="0" cellpadding="5" width="65%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;taskdef classpath="cobertura.jar" resource="tasks.properties" /&gt;</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>然后，需要一个 <code>cobertura-instrument</code> 任务，该任务将在已经编译好的类文件中添加日志代码。<code>todir</code> 属性指定将测量类放到什么地方。<code>fileset</code> 子元素指定测量哪些 .class 文件： </p>
		<table cellspacing="0" cellpadding="5" width="65%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;target name="instrument"&gt;
  &lt;cobertura-instrument todir="target/instrumented-classes"&gt;
    &lt;fileset dir="target/classes"&gt;
      &lt;include name="**/*.class"/&gt;
    &lt;/fileset&gt;
  &lt;/cobertura-instrument&gt;
&lt;/target&gt;</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>用通常运行测试包的同一种类型的 Ant 任务运行测试。惟一的区别在于：被测量的类必须在原始类出现在类路径中之前出现在类路径中，而且需要将 Cobertura JAR 文件添加到类路径中： </p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;target name="cover-test" depends="instrument"&gt;
  &lt;mkdir dir="${testreportdir}" /&gt;
  &lt;junit dir="./" failureproperty="test.failure" printSummary="yes" 
         fork="true" haltonerror="true"&gt;
    &lt;!-- 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. --&gt;
    &lt;classpath location="cobertura.jar"/&gt;
    &lt;classpath location="target/instrumented-classes"/&gt;
    &lt;classpath&gt;
      &lt;fileset dir="${libdir}"&gt;
        &lt;include name="*.jar" /&gt;
      &lt;/fileset&gt;
      &lt;pathelement path="${testclassesdir}" /&gt;
      &lt;pathelement path="${classesdir}" /&gt;
    &lt;/classpath&gt;
    &lt;batchtest todir="${testreportdir}"&gt;
      &lt;fileset dir="src/java/test"&gt;
        &lt;include name="**/*Test.java" /&gt;
        &lt;include name="org/jaxen/javabean/*Test.java" /&gt;
      &lt;/fileset&gt;
    &lt;/batchtest&gt;
  &lt;/junit&gt;
&lt;/target&gt;&gt;</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Jaxen 项目使用 JUnit 作为其测试框架，但是 Cobertura 是不受框架影响的。它在 TestNG、Artima SuiteRunner、HTTPUni 或者在您自己在地下室开发的系统中一样工作得很好。</p>
		<p>最后，<code>cobertura-report</code> 任务生成本文开始部分看到的那个 HTML 文件： </p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;target name="coverage-report" depends="cover-test"&gt;
 &lt;cobertura-report srcdir="src/java/main" destdir="cobertura"/&gt;
&lt;/target&gt;</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>srcdir</code> 属性指定原始的 .java 源代码在什么地方。<code>destdir</code> 属性指定 Cobertura 放置输出 HTML 的那个目录的名称。</p>
		<p>在自己的 Ant 编译文件中加入了类似的任务后，就可以通过键入以下命令来生成一个覆盖报告： </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>当然，如果您愿意的话，还可以改变目标任务的名称，或者将这三项任务合并为一个目标任务。 </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" href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101CE">
						<span class="atitle">
								<font face="Arial" size="4">结束语</font>
						</span>
				</a>
		</p>
		<p>Cobertura 是敏捷程序员工具箱中新增的一个重要工具。通过生成代码覆盖率的具体数值，Cobertura 将单元测试从一种艺术转变为一门科学。它可以寻找测试覆盖中的空隙，直接找到 bug。测量代码覆盖率使您可以获得寻找并修复 bug 所需的信息，从而开发出对每个人来说都更健壮的软件。 </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" href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font face="Arial" size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-cobertura/" target="_blank"><font color="#5c81a7">英文原文</font></a>。<br /><br /></li>
				<li>从 SourceForge 下载 <a href="http://cobertura.sourceforge.net/"><font color="#996699">Cobertura</font></a>。<br /><br /></li>
				<li>获得 <a href="http://www.junit.org/"><font color="#5c81a7">JUnit</font></a><a href="http://junit.sourceforge.net/doc/testinfected/testing.htm"><font color="#5c81a7">受影响的测试</font></a>，它是用于 Java 平台的实际标准单元测试框架。<br /><br /></li>
				<li>阅读 Dave Thomas 和 Andy Hunt 合著的 <a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0974514012"><font color="#5c81a7"><i>Pragmatic Unit Testing in Java With JUnit</i></font></a>（Pragmatic Bookshelf，2003）。<br /><br /></li>
				<li>Cenqua 的 <a href="http://www.cenqua.com/clover/"><font color="#5c81a7">Clover</font></a> 是一个更精致的、收费的测试覆盖率工具，它所做的工作实质上与 Cobertura 相同，只是它做得更细致一些。<br /><br /></li>
				<li>IBM Rational 提供了全面的测试工具包来帮助您检测代码。“<a href="http://www.ibm.com/developerworks/rational/library/274.html"><font color="#5c81a7">Get started with automated testing: Road map to success</font></a>”为您提供了即刻开始测试自己的代码所需的基础知识。 <br /><br /></li>
				<li>Mike Kelly 提供了“<a href="http://www.ibm.com/developerworks/rational/library/568.html"><font color="#5c81a7">using TestManager to report test coverage</font></a>”的细节（developerWorks，2003 年 12 月）。<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/rational/products/purifyplus">
								<font color="#5c81a7">PureCoverage</font>
						</a> 是 IBM Rational PurifyPlus 测试工具包的一部分，它是一个出色的代码覆盖率工具。Rational Application Developor 包括 PureCoverage 功能，从“<a href="http://www-128.ibm.com/developerworks/cn/rational/kelly-stoker/"><font color="#5c81a7">使用 IBM Rational Application Developer for WebSphere Software 进行组件测试</font></a>”中可以了解关于它的更多知识（developerWorks，2005 年 3 月）。<br /><br /></li>
				<li>Cobertura 是 <a href="http://www.jcoverage.com/"><font color="#5c81a7">jcoverage</font></a> 的分支。 <br /><br /></li>
				<li>Carnegie Mellon 的 Software Engineering Institute 发表了对 <a href="http://www.sei.cmu.edu/str/descriptions/cyclomatic_body.html"><font color="#996699">McCabe's Cyclomatic Complexity</font></a> 的详细说明。<br /><br /></li>
				<li>David Carew 和 Sandeep Desai 合著的 “<a href="http://www.ibm.com/developerworks/edu/i-dw-wes-junit-i.html?S_TACT=105AGX02"><font color="#5c81a7">Keeping critters out of your code: How to use WebSphere and JUnit to prevent programming bugs</font></a>”（developerWorks，2003 年 6 月） 分析了如何用 XP 方法进行测试。<br /><br /></li>
				<li>Dennis M. Sosnoski <a href="http://www-128.ibm.com/developerworks/cn/java/j-cwt02095/"><font color="#5c81a7">推出</font></a> 了 <a href="http://www-128.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=Classworking+%E5%B7%A5%E5%85%B7%E7%AE%B1%3A"><font color="#5c81a7">Classworking 工具箱</font></a> 系列，探讨开源的 <a href="http://hansel.sourceforge.net/"><font color="#5c81a7">Hansel</font></a> 和 <a href="http://www.cs.uoregon.edu/research/perpetual/dasada/Software/Gretel/"><font color="#5c81a7">Gretel</font></a> 代码覆盖率工具。<br /><br /></li>
				<li>参阅“<a href="http://www.ibm.com/developerworks/java/library/j-jester/"><font color="#5c81a7">Test your tests with Jester</font></a>”，了解关于开放源代码 JUnit 测试测试器的知识。<br /><br /></li>
				<li>Malcolm Davis 撰写的“<a href="http://www-128.ibm.com/developerworks/cn/java/j-ant/"><font color="#5c81a7">利用 Ant 和 JUnit 进行增量开发</font></a>”（developerWorks，2000 年 11 月）介绍了如何将 JUnit 集成到自己的项目中。<br /><br /></li>
				<li>Eric Allen 和 Roy Miller 在他们各自的专栏 <a href="http://www-128.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=%E8%AF%8A%E6%96%AD+Java+%E4%BB%A3%E7%A0%81%EF%BC%9A"><font color="#5c81a7">诊断 Java 代码</font></a> 和 <a href="http://www.ibm.com/developerworks/java/library/j-xpcol.html"><font color="#5c81a7">Demystifying Extreme Programming</font></a> 中经常讨论到单元测试。<br /><br /></li>
				<li>Erik Hatcher 的 <a href="http://www-128.ibm.com/developerworks/cn/java/j-junitmail/"><font color="#5c81a7">让编译和测试过程自动化</font></a> （developerWorks，2001 年 8 月）展示了如何将增量测试和连续编译结合到一个自动过程中。<br /><br /></li>
				<li>探索 <a href="http://alphaworks.ibm.com/tech/focus"><font color="#5c81a7">FoCuS</font></a>，这是 IBM alphaWorks 的一个工具，它实现了功能覆盖方法，并通过提供未测试区域的详细覆盖率信息来改进应用程序测试。<br /><br /></li>
				<li>作为本文分析对象的 <a href="http://jaxen.codehaus.org/"><font color="#5c81a7">Jaxen 项目</font></a> 是一个用于 Java 编程的开源 XPath 引擎，适合多种不同对象模型。 <br /><br /></li>
				<li>在 developerWorks 的 <a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7">Java 技术专区</font></a> 中可以找到关于 Java 编程的各个方面的文章。<br /><br /></li>
				<li>请参阅 <a href="http://devworks.krcinfo.com/"><font color="#5c81a7">Developer Bookstore</font></a>，以获得一些技术书籍的完整清单，其中包括数百本 <a href="http://devworks.krcinfo.com/WebForms/ProductList.aspx?Search=Category&amp;id=1200"><font color="#5c81a7">Java 相关主题</font></a> 的书籍。<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" href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span 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 出生在新奥尔良，现在他还定期回老家喝一碗美味的秋葵汤。不过目前，他和妻子 Beth 定居在纽约临近布鲁克林的 Prospect Heights，同住的还有他的猫咪 Charm（取自夸克）和 Marjorie（取自他岳母的名字）。他是 Polytechnic 大学计算机科学的副教授，讲授 Java 技术和面向对象编程。他的 <a href="http://www.cafeaulait.org/"><font color="#5c81a7">Cafe au Lait</font></a> 网站是 Internet 上最受欢迎的独立 Java 站点之一，姊妹站点 <a href="http://www.cafeconleche.org/"><font color="#5c81a7">Cafe con Leche</font></a> 已经成为最受欢迎的 XML 站点之一。他的著作包括 <a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0321150406"><font color="#5c81a7"><i>Effective XML</i></font></a>、<a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=0201771861"><font color="#5c81a7"><i>Processing XML with Java</i></font></a>、<a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=1565928709"><font color="#5c81a7"><i>Java Network Programming</i></font></a>和 <a href="http://www.cafeconleche.org/books/bible3/"><font color="#5c81a7"><i>The XML 1.1 Bible</i></font></a>。目前他正在从事 XML 的 <a href="http://www.xom.nu/"><font color="#5c81a7">XOM</font></a> API、<a href="http://jaxen.codehaus.org/"><font color="#5c81a7">Jaxen</font></a> XPath 引擎和 <a href="http://jester.sourceforge.net/"><font color="#5c81a7">Jester</font></a> 测试覆盖率工具的开发工作。 </p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/supsky/aggbug/58967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-19 12:52 <a href="http://www.blogjava.net/supsky/archive/2006/07/19/58967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转贴）不要被覆盖报告所迷惑</title><link>http://www.blogjava.net/supsky/archive/2006/07/19/58965.html</link><dc:creator>eddy liao</dc:creator><author>eddy liao</author><pubDate>Wed, 19 Jul 2006 04:48:00 GMT</pubDate><guid>http://www.blogjava.net/supsky/archive/2006/07/19/58965.html</guid><wfw:comment>http://www.blogjava.net/supsky/comments/58965.html</wfw:comment><comments>http://www.blogjava.net/supsky/archive/2006/07/19/58965.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/supsky/comments/commentRss/58965.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/supsky/services/trackbacks/58965.html</trackback:ping><description><![CDATA[
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<h1>
												<span style="COLOR: #999999">
														<u>
																<font color="#000000" size="5">
																</font>
														</u>
												</span>
										</h1>
										<h1>
												<span style="COLOR: #999999">
														<a href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#N10149">
																<font color="#000000" size="5">http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#N10149</font>
														</a>
												</span>
										</h1>
										<h1>
												<span style="COLOR: #999999">追求代码质量: </span>不要被覆盖报告所迷惑</h1>
										<p id="subtitle">您是否曾被测试覆盖度量引入歧途？</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="测试覆盖工具对单元测试具有重要的意义，但是经常被误用。这个月，Andrew Glover 会在他的新系列 —— “追求代码质量” 中向您介绍值得参考的专家意见。第一部分深入地介绍覆盖报告中数字的真实含义。然后他会提出您可以尽早并经常地利用覆盖来确保代码质量的三个方法。" name="body" />
																														<input type="hidden" value="追求代码质量: 不要被覆盖报告所迷惑" 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="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//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 height="1" alt="" src="//www.ibm.com/i/c.gif" width="8" />
																																				</td>
																																				<td width="16">
																																						<img height="16" alt="" src="//www.ibm.com/i/c.gif" width="16" />
																																				</td>
																																				<td class="small" width="122">
																																						<p>
																																								<span class="ast">未显示需要 JavaScript 的文档选项</span>
																																						</p>
																																				</td>
																																		</tr>
																																</noscript>
																														</tbody>
																												</form>
																												<tbody>
																														<tr valign="top">
																																<td width="8">
																																		<font color="#5c81a7" size="2">
																																				<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																		</font>
																																</td>
																																<td width="16">
																																		<font color="#5c81a7" size="2">
																																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" />
																																		</font>
																																</td>
																																<td width="122">
																																		<p>
																																				<a class="smallplainlink" href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
																																						<b>
																																								<font color="#996699" size="2">讨论</font>
																																						</b>
																																				</a>
																																		</p>
																																</td>
																														</tr>
																												</tbody>
																										</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" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#author">
						<font color="#996699">Andrew Glover</font>
				</a>, CTO, Vanward Technologies<br /></p>
		<p>2006 年 2 月 06 日</p>
		<blockquote>测试覆盖工具对单元测试具有重要的意义，但是经常被误用。这个月，Andrew Glover 会在他的新系列 —— <i>追求代码质量</i> 中向您介绍值得参考的专家意见。第一部分深入地介绍覆盖报告中数字的真实含义。然后他会提出您可以尽早并经常地利用覆盖来确保代码质量的三个方法。</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>您还记得以前大多数开发人员是如何追求代码质量的吗。在那时，有技巧地放置 <code>main()</code> 方法被视为灵活且适当的测试方法。经历了漫长的道路以后，现在自动测试已经成为高质量代码开发的基本保证，对此我很感谢。但是这还不是我所要感谢的全部。Java™ 开发人员现在拥有很多通过代码度量、静态分析等方法来度量代码质量的工具。我们甚至已经设法将重构分类成一系列便利的模式！</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">要获得有关代码质量问题的答案，您可以访问由 Andrew Glover 主持的 <a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10"><font color="#996699">Code Quality</font></a> 论坛。 </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>所有的这些新的工具使得确保代码质量比以前简单得多，不过您还需要知道如何使用它们。在这个系列中，我将重点阐述有关保证代码质量的一些有时看上去有点神秘的东西。除了带您一起熟悉有关代码质量保证的众多工具和技术之外，我还将为您说明：</p>
		<ul>
				<li>定义并有效度量最影响质量的代码方面。 
</li>
				<li>设定质量保证目标并照此规划您的开发过程。 
</li>
				<li>确定哪个代码质量工具和技术可以满足您的需要。 
</li>
				<li>实现最佳实践（清除不好的），使确保代码质量<i>及早并经常地</i> 成为开发实践中轻松且有效的方面。 </li>
		</ul>
		<p>在这个月，我将首先看看 Java 开发人员中最流行也是最容易的质量保证工具包：测试覆盖度量。</p>
		<p>
				<a name="N1008B">
						<span class="atitle">
								<font face="Arial" size="4">谨防上当</font>
						</span>
				</a>
		</p>
		<p>这是一个晚上鏖战后的早晨，大家都站在饮水机边上。开发人员和管理人员们了解到一些经过良好测试的类可以达到超过 90% 的覆盖率，正在高兴地互换着 NFL 风格的点心。团队的集体信心空前高涨。从远处可以听到 “放任地重构吧” 的声音，似乎缺陷已成为遥远的记忆，响应性也已微不足道。但是一个很小的反对声在说：</p>
		<p>
				<i>女士们，先生们，不要被覆盖报告所愚弄</i>。</p>
		<p>现在，不要误解我的意思：并不是说使用测试覆盖工具是愚蠢的。对单元测试范例，它是很重要的。不过更重要的是您如何理解所得到的信息。许多开发团队会在这儿犯第一个错。</p>
		<p>高覆盖率只是表示执行了很多的代码，并不意味着这些代码被<i>很好地</i> 执行。如果您关注的是代码的质量，就必须精确地理解测试覆盖工具能做什么，不能做什么。然后您才能知道如何使用这些工具去获取有用的信息。而不是像许多开发人员那样，只是满足于高覆盖率。</p>
		<a name="N100A2">
				<span class="atitle">
						<font face="Arial" size="4">
								<br />测试覆盖度量</font>
				</span>
		</a>
		<p>测试覆盖工具通常可以很容易地添加到确定的单元测试过程中，而且结果可靠。下载一个可用的工具，对您的 Ant 和 Maven 构建脚本作一些小的改动，您和您的同事就有了在饮水机边上谈论的一种新报告：<i>测试覆盖报告</i>。当 <code>foo</code> 和 <code>bar</code> 这样的程序包令人惊奇地显示<i>高</i> 覆盖率时，您可以得到不小的安慰。如果您相信至少您的部分代码可以保证是 “没有 BUG” 的，您会觉得很安心。但是这样做是一个错误。</p>
		<p>存在不同类型的覆盖度量，但是绝大多数的工具会关注<i>行覆盖</i>，也叫做<i>语句覆盖</i>。此外，有些工具会报告<i>分支覆盖</i>。通过用一个测试工具执行代码库并捕获整个测试过程中与被 “触及” 的代码对应的数据，就可以获得测试覆盖度量。然后这些数据被合成为覆盖报告。在 Java 世界中，这个测试工具通常是 JUnit 以及名为 Cobertura、Emma 或 Clover 等的覆盖工具。</p>
		<p>
				<i>行覆盖</i>只是指出代码的哪些行被执行。如果一个方法有 10 行代码，其中的 8 行在测试中被执行，那么这个方法的行覆盖率是 80%。这个过程在总体层次上也工作得很好：如果一个类有 100 行代码，其中的 45 行被触及，那么这个类的行覆盖率就是 45%。同样，如果一个代码库包含 10000 个非注释性的代码行，在特定的测试运行中有 3500 行被执行，那么这段代码的行覆盖率就是 35%。</p>
		<p>报告<i>分支覆盖</i> 的工具试图度量决策点（比如包含逻辑 <code>AND</code> 或 <code>OR</code> 的条件块）的覆盖率。与行覆盖一样，如果在特定方法中有两个分支，并且两个分支在测试中都被覆盖，那么您可以说这个方法有 100% 的分支覆盖率。</p>
		<p>问题是，这些度量有什么用？很明显，很容易获得所有这些信息，不过您需要知道如何使用它们。一些例子可以阐明我的观点。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100DB">
						<span class="atitle">
								<font face="Arial" size="4">代码覆盖在活动</font>
						</span>
				</a>
		</p>
		<p>我在清单 1 中创建了一个简单的类以具体表述类层次的概念。一个给定的类可以有一连串的父类，例如 <code>Vector</code>，它的父类是 <code>AbstractList</code>，<code>AbstractList</code> 的父类又是 <code>AbstractCollection</code>，<code>AbstractCollection</code> 的父类又是 <code>Object</code>：</p>
		<br />
		<a name="code1">
				<b>清单 1. 表现类层次的类</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">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;
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>正如您看到的，清单 1 中的 <code>Hierarchy</code> 类具有一个 <code>baseClass</code> 实例以及它的父类的集合。清单 2 中的 <code>HierarchyBuilder</code> 通过两个复制 <code>buildHierarchy</code> 的重载的 <code>static</code> 方法创建了 <code>Hierarchy</code> 类。</p>
		<br />
		<a name="code2">
				<b>清单 2. 类层次生成器</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">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 &amp;&amp; superclass.getName().equals("java.lang.Object")){
       return hier; 
    }else{      
       while((clzz.getSuperclass() != null) &amp;&amp; 
          (!clzz.getSuperclass().getName().equals("java.lang.Object"))){
             clzz = clzz.getSuperclass();
             hier.addClass(clzz);
       }	        
       return hier;
    }
  }      
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<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" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1012B">
						<span class="atitle">
								<font face="Arial" size="4">现在是测试时间！</font>
						</span>
				</a>
		</p>
		<p>有关测试覆盖的文章怎么能缺少测试案例呢？在清单 3 中，我定义了一个简单的有三个测试案例的 JUnit 测试类，它将试图执行 <code>Hierarchy</code> 类和 <code>HierarchyBuilder</code> 类：</p>
		<br />
		<a name="code3">
				<b>清单 3. 测试 HierarchyBuilder！</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">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]);      
  }
 
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>因为我是一个狂热的测试人员，我自然希望运行一些覆盖测试。对于 Java 开发人员可用的代码覆盖工具中，我比较喜欢用 Cobertura，因为它的报告很友好。而且，Corbertura 是开放源码项目，它派生出了 JCoverage 项目的前身。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10149">
						<span class="atitle">
								<font face="Arial" size="4">Cobertura 的报告</font>
						</span>
				</a>
		</p>
		<p>运行 Cobertura 这样的工具和运行您的 JUnit 测试一样简单，只是有一个用专门逻辑在测试时检查代码以报告覆盖率的中间步骤（这都是通过工具的 Ant 任务或 Maven 的目标完成的）。</p>
		<p>正如您在图 1 中看到的，<code>HierarchyBuilder</code> 的覆盖报告说明部分代码<i>没有</i> 被执行。事实上，Cobertura 认为 <code>HierarchyBuilder</code> 的行覆盖率为 59%，分支覆盖率为 75%。</p>
		<br />
		<a name="N10162">
				<b>图 1. Cobertura 的报告</b>
		</a>
		<br />
		<img height="718" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-01-1.gif" width="572" border="0" />
		<br />
		<p>这样看来，我的第一次覆盖测试是失败的。首先，带有 <code>String</code> 参数的 <code>buildHierarchy()</code> 方法根本没有被测试。其次，另一个 <code>buildHierarchy()</code> 方法中的两个条件都没有被执行。有趣的是，所要关注的正是第二个没有被执行的 <code>if</code> 块。</p>
		<p>因为我所需要做的只是增加一些测试案例，所以我并不担心这一点。一旦我到达了所关注的区域，我就可以很好地完成工作。注意我这儿的逻辑：我使用测试报告来了解什么<i>没有</i> 被测试。现在我已经可以选择使用这些数据来增强测试或者继续工作。在本例中，我准备增强我的测试，因为我还有一些重要的区域未覆盖。</p>
		<p>
				<a name="N1018A">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Cobertura：第二轮</font>
								</strong>
						</span>
				</a>
		</p>
		<p>清单 4 是一个更新过的 JUnit 测试案例，增加了一些附加测试案例，以试图完全执行 <code>HierarchyBuilder</code>： </p>
		<br />
		<a name="code4">
				<b>清单 4. 更新过的 JUnit 测试案例</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">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){}
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当我使用新的测试案例再次执行测试覆盖过程时，我得到了如图 2 所示的更加完整的报告。现在，我覆盖了未测试的 <code>buildHierarchy()</code> 方法，也处理了另一个 <code>buildHierarchy()</code> 方法中的两个 <code>if</code> 块。然而，因为 <code>HierarchyBuilder</code> 的构造器是 <code>private</code> 类型的，所以我不能通过我的测试类测试它（我也不关心）。因此，我的行覆盖率仍然只有 88%。</p>
		<br />
		<a name="N101BA">
				<b>图 2. 谁说没有第二次机会</b>
		</a>
		<br />
		<img height="709" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-01.gif" width="569" border="0" />
		<br />
		<p>正如您看到的，使用一个代码覆盖工具<i>可以</i> 揭露重要的没有相应测试案例的代码。重要的事情是，在阅读报告（<i>特别</i> 是覆盖率高的）时需要小心，它们也许隐含危险的信息。让我们看看两个例子，看看在高覆盖率后面隐藏着什么。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101D2">
						<span class="atitle">
								<font face="Arial" size="4">条件带来的麻烦</font>
						</span>
				</a>
		</p>
		<p>正如您已经知道的，代码中的许多变量可能有多种状态；此外，条件的存在使得执行有多条路径。在留意这些问题之后，我将在清单 5 中定义一个极其简单只有一个方法的类：</p>
		<br />
		<a name="code5">
				<b>清单 5.您能看出下面的缺陷吗？ </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">package com.vanward.coverage.example01;

public class PathCoverage {

  public String pathExample(boolean condition){
    String value = null;
    if(condition){
      value = " " + condition + " ";
    }
    return value.trim();
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您是否发现了清单 5 中有一个隐藏的缺陷呢？如果没有，不要担心，我会在清单 6 中写一个测试案例来执行 <code>pathExample()</code> 方法并确保它正确地工作： </p>
		<br />
		<a name="code1">
				<b>清单 6. JUnit 来救援！ </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">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);
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>我的测试案例正确运行，我的神奇的代码覆盖报告（如下面图 3 所示）使我看上去像个超级明星，测试覆盖率达到了 100%！</p>
		<br />
		<a name="#figure3">
				<b>图 3. 覆盖率明星 </b>
		</a>
		<br />
		<img height="399" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-ex01.gif" width="515" border="0" />
		<br />
		<p>我想现在应该到饮水机边上去说了，但是等等，我不是怀疑代码中有什么缺陷呢？认真检查清单 5 会发现，如果 <code>condition</code> 为 <code>false</code>，那么第 13 行确实会抛出 <code>NullPointerException</code>。<i>Yeesh</i>，这儿发生了什么？</p>
		<p>这表明行覆盖的确不能很好地指示测试的有效性。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1021F">
						<span class="atitle">
								<font face="Arial" size="4">路径的恐怖</font>
						</span>
				</a>
		</p>
		<p>在清单 7 中，我定义了另一个包含 <i>indirect</i> 的简单例子，它仍然有不能容忍的缺陷。请注意 <code>branchIt()</code> 方法中 <code>if</code> 条件的后半部分。（<code>HiddenObject</code> 类将在清单 8 中定义。）</p>
		<br />
		<a name="code1">
				<b>清单 7. 这个代码足够简单</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">package com.vanward.coverage.example02;

import com.acme.someotherpackage.HiddenObject;

public class AnotherBranchCoverage {
   
  public void branchIt(int value){
    if((value &gt; 100) || (HiddenObject.doWork() == 0)){
      this.dontDoIt();
    }else{
      this.doIt();
    }
  }                             

  private void dontDoIt(){
    //don't do something...
  }

  private void doIt(){
    //do something!
  }   
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>呀！清单 8 中的 <code>HiddenObject</code> 是<i>有害的</i>。与清单 7 中一样，调用 <code>doWork()</code> 方法会导致 <code>RuntimeException</code>：</p>
		<br />
		<a name="code1">
				<b>清单 8. 上半部分！ </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">package com.acme.someotherpackage.HiddenObject;

public class HiddenObject {

  public static int doWork(){
    //return 1;
    throw new RuntimeException("surprise!");
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>但是我的确可以通过一个良好的测试捕获这个异常！在清单 9 中，我编写了另一个好的测试，以图挽回我的超级明星光环：</p>
		<br />
		<a name="code1">
				<b>清单 9. 使用 JUnit 规避风险</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">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);
  }    
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您对这个测试案例有什么想法？您也许会写出更多的测试案例，但是请设想一下清单 7 中不确定的条件有不止一个的缩短操作会如何。设想如果前半部分中的逻辑比简单的 <code>int</code> 比较更复杂，那么<i>您</i> 需要写多少测试案例才能满意？</p>
		<p>
				<a name="N10274">
						<span class="smalltitle">
								<strong>
										<font face="Arial">仅仅给我数字</font>
								</strong>
						</span>
				</a>
		</p>
		<p>现在，对清单 7、8、9 的测试覆盖率的分析结果不再会使您感到惊讶。在图 4 的报告中显示我达到了 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是，我执行了第 10 行！</p>
		<br />
		<a name="N1027F">
				<b>图 4.愚弄的报酬</b>
		</a>
		<br />
		<img height="497" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-ex02.gif" width="528" border="0" />
		<br />
		<p>从第一印象看，这让我骄傲。但是这个报告有什么误导吗？只是粗略地看一看报告中的数字，会导致您相信代码是经过<i>良好测试的</i>。基于这一点，您也许会认为出现缺陷的风险很低。这个报告并不能帮助您确定 <code>or</code> 缩短操作的后半部分是一个定时炸弹！</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10298">
						<span class="atitle">
								<font face="Arial" size="4">质量测试</font>
						</span>
				</a>
		</p>
		<p>我不止一次地说：您可以（而且应该）使用测试覆盖工具作为您的测试过程的一部分。但是<i>不要被覆盖报告所愚弄</i>。关于覆盖报告您需要了解的主要事情是，覆盖报告最好用来检查哪些代码<i>没有经过</i> 充分的测试。当您检查覆盖报告时，找出较低的值，并了解为什么特定的代码没有经过充分的测试。知道这些以后，开发人员、管理人员以及 QA 专业人员就可以在真正需要的地方使用测试覆盖工具。通常有下列三种情况：</p>
		<ul>
				<li>估计修改已有代码所需的时间 
</li>
				<li>评估代码质量 
</li>
				<li>评定功能测试 </li>
		</ul>
		<p>现在我可以断定对测试覆盖报告的一些使用方法会将您引入歧途，下面这些最佳实践可以使得测试覆盖报告可以真正为您所用。</p>
		<p>
				<a name="N102B6">
						<span class="smalltitle">
								<strong>
										<font face="Arial">1. 估计修改已有代码所需的时间</font>
								</strong>
						</span>
				</a>
		</p>
		<p>对一个开发团队而言，针对代码编写测试案例自然可以增加集体的信心。与没有相应测试案例的代码相比，经过测试的代码更容易重构、维护和增强。测试案例因为暗示了代码在测试工作中是<i>如何</i> 工作的，所以还可以充当内行的文档。此外，如果被测试的代码发生改变，测试案例通常也会作相应的改变，这与诸如注释和 Javadoc 这样的静态代码文档不同。</p>
		<p>在另一方面，没有经过相应测试的代码更难于理解和<i>安全地</i> 修改。因此，知道代码有没有被测试，并看看实际的测试覆盖数值，可以让开发人员和管理人员更准确地预知修改已有代码所需的时间。</p>
		<p>再次回到饮水机边上，可以更好地阐明我的观点。</p>
		<blockquote>市场部的 Linda：“我们想让系统在用户完成一笔交易时做 <i>x</i> 工作。这需要多长时间。我们的用户需要尽快实现这一功能。” <br /><br />管理人员 Jeff：“让我看看，这个代码是 Joe 在几个月前编写的，需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成这项工作。” <br /><br />Linda：“Joe？他是谁？” <br /><br />Jeff：“哦，Joe，因为他不知道自己在干什么，所以被我解雇了。” </blockquote>
		<p>情况似乎有点不妙，不是吗？尽管如此，Jeff 还是将任务分配给了 Mary，Mary 也认为能够在两天内完成工作 —— 确切地说，在看到代码之前她是这么认为的。</p>
		<blockquote>Mary：“Joe 写这些代码时是不是<i>睡着了</i>？这是我所见过的最差的代码。我甚至不能确认这是 Java 代码。除非推倒重来，要不我根本没法修改。” </blockquote>
		<p>情况对 “饮水机” 团队不妙，不是吗？但是我们假设，如果在这个不幸的事件的当初，Jeff 和 Mary 就拥有一份测试报告，那么情况会如何呢？当 Linda 要求实现新功能时，Jeff 做的第一件事就是检查以前生成的覆盖报告。注意到需要改动的软件包几乎没有被覆盖，然后他就会与 Mary 商量。</p>
		<blockquote>Jeff：“Joe 编写的这个代码很差，绝大多数没经过测试。您认为要支持 Linda 所说的功能需要多长时间？” <br /><br />Mary：“这个代码很混乱。我甚至都不想看到它。为什么不让 Mark 来做呢？” <br /><br />Jeff：“因为 Mark 不编写测试，刚被我解雇了。我需要您测试这个代码并作一些改动。告诉我您需要多长时间。” <br /><br />Mary：“我至少需要两天编写测试，然后我会重构这个代码，增加新的功能。我想总共需要四天吧。” </blockquote>
		<p>正如他们所说的，知识的力量是强大的。开发人员可以在试图修改代码<i>之前</i> 使用覆盖报告来检查代码质量。同样，管理人员可以使用覆盖数据更好地估计开发人员实际所需的时间。</p>
		<p>
				<a name="N102F8">
						<span class="smalltitle">
								<strong>
										<font face="Arial">2. 评估代码质量</font>
								</strong>
						</span>
				</a>
		</p>
		<p>开发人员的测试可以降低代码中存在缺陷的风险，因此现在很多开发团队在新开发和更改代码的同时需要编写单元测试。然而正如前面所提到的 Mark 一样，并不总是在编码的同时进行单元测试，因而会导致低质量代码的出现。</p>
		<p>监控覆盖报告可以帮助开发团队迅速找出不断增长的<i>没有</i> 相应测试的代码。例如，在一周开始时运行覆盖报告，显示项目中一个关键的软件包的覆盖率是 70%。如果几天后，覆盖率下降到了 60%，那么您可以推断：</p>
		<ul>
				<li>软件包的代码行增加了，但是没有为新代码编写相应的测试（或者是新增加的测试不能有效地覆盖新代码）。<br /><br /></li>
				<li>删除了测试案例。<br /><br /></li>
				<li>上述两种情况都发生了。 </li>
		</ul>
		<p>能够监控事情的发展，无疑是件好事。定期地查阅报告使得设定目标（例如获得覆盖率、维护代码行的测试案例的比例等）并监控事情的发展变得更为容易。如果您发现测试没有如期编写，您可以提前采取一些行动，例如对开发人员进行培训、指导或帮助。与其让用户 “在使用中” 发现程序缺陷（这些缺陷本应该在几个月前通过简单的测试暴露出来），或者等到管理人员发现没有编写单元测试时再感到惊讶（和愤怒），还不如采取一些预防性的措施。</p>
		<p>使用覆盖报告来确保正确的测试是一项伟大的实践。关键是要训练有素地完成这项工作。例如，使每晚生成并查阅覆盖报告成为<i>连续累计</i> 过程的一部分。</p>
		<p>
				<a name="N10320">
						<span class="smalltitle">
								<strong>
										<font face="Arial">3. 评定功能测试</font>
								</strong>
						</span>
				</a>
		</p>
		<p>假设覆盖报告在指出<i>没有经过</i> 足够测试的代码部分方面非常有效，那么质量保证人员可以使用这些数据来评定与功能测试有关的关注区域。让我们回到 “饮水机” 团队来看看 QA 的负责人 Drew 是如何评价 Joe 的代码的：</p>
		<blockquote>Drew 对 Jeff 说：“我们为下一个版本编写了测试案例，我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。” <br /><br />Jeff：“哦，我们在这个领域有好些问题。如果我是一个赌徒的话，我会对这个功能区域给予特别的关注。Mary 正在对这个应用程序做一些其他的修改 —— 她在编写单元测试方面做得很好，但是这个代码也太差了点。” <br /><br />Drew：“是的，我正在确定工作的资源和级别，看上去我没必要那么担心了，我估计我们的团队会对股票交易模块引起足够的关注。” </blockquote>
		<p>知识再次显示了其强大的力量。与其他软件生命周期中的风险承担者（例如 QA）配合，您可以利用覆盖报告所提供的信息来降低风险。在上面的场景中，也许 Jeff 可以为 Drew 的团队提供一个早期的不包含 Mary 的所有修改的版本。不过无论如何，Drew 的团队都应该关注应用程序的股票交易方面，与其他具有相应单元测试的代码相比，这个地方似乎存在更大的缺陷风险。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10338">
						<span class="atitle">
								<font face="Arial" size="4">测试有什么好处</font>
						</span>
				</a>
		</p>
		<p>对单元测试范例而言，测试覆盖度量工具是一个有点奇怪的组成部分。对于一个已存在的有益的过程，覆盖度量可以增加其深度和精度。然而，您应该仔细地阅读代码覆盖报告。单独的高覆盖率并不能确保代码的质量。对于减少缺陷，代码的高覆盖并不是必要条件，尽管高覆盖的代码的确<i>更少</i> 有缺陷。</p>
		<p>测试覆盖度量的窍门是使用覆盖报告找出<i>未经</i> 测试的代码，分别在微观和宏观两个级别。通过从顶层开始分析您的代码库，以及分析单个类的覆盖，可以促进深入的覆盖测试。一旦您能够综合这些原则，您和您的组织就可以在真正需要的地方使用覆盖度量工具，例如估计一个项目所需的时间，持续监控代码质量以及促进与 QA 的协作。</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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font face="Arial" size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
								<font color="#996699">参与论坛讨论</font>
						</a>。<br /><br /></li>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-cq01316/" target="_blank"><font color="#5c81a7">英文原文</font></a>。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/"><font color="#996699">用 Cobertura 测量测试覆盖率</font></a>”（Elliotte Rusty Harold，developerWorks，2005 年 5 月）：找出存在 bug 的未经测试的代码。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-cwt02095/"><font color="#5c81a7">Classworking 工具箱: 用 Hansel 和 Gretel 覆盖代码</font></a>”（Dennis Sosnoski，developerWorks，2005 年 2 月）：如何完成您的单元测试？使用代码覆盖工具找出答案！<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-jester/"><font color="#5c81a7">用 Jester 对测试进行测试</font></a>”（Elliotte Rusty Harold，developerWorks，2005 年 5 月）：Jester 擅长发现测试套件的问题，对代码库的结构方面有独特的洞察力。<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/rational/library/4995.html"><font color="#5c81a7">The business value of software quality</font></a>”（Geoffrey Bessin，The Rational Edge，2004 年 6 月）：描述 IBM Rational 有关提高代码质量的主张并列举出用来保证质量的主要工具。<br /><br /></li>
				<li>
						<a href="http://www-128.ibm.com/developerworks/cn/java/">
								<font color="#5c81a7">Java 技术专区</font>
						</a>：数百篇有关 Java 编程各方面的文章。 </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" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span 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">
														<img alt="" src="http://www.ibm.com/developerworks/i/p-aglover.jpg" align="left" border="0" name="Photo of Andrew Glover" />
												</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>Andrew Glover 是 <a href="http://www.vanwardtechnologies.com/"><font color="#5c81a7">Vanward Technologies</font></a> 公司的 CTO，该公司位于华盛顿特区大都会地区，公司的专业领域是自动测试框架的构造，自动测试框架可以降低软件 bug 数量，减少集成和测试的时间，提高整体的代码稳定性。他还是 <a href="http://www.amazon.com/gp/product/047144846X/104-1464220-8871162?n=283155"><font color="#5c81a7">Java Testing Patterns</font></a>（Wiley，2004 年 9 月）的合著者</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/supsky/aggbug/58965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/supsky/" target="_blank">eddy liao</a> 2006-07-19 12:48 <a href="http://www.blogjava.net/supsky/archive/2006/07/19/58965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>