如果硬编码 _reports 目录,那么当我决定将 Simian 报告放到另一个目录时,会很麻烦。而且,如果其他工具在脚本的其他地方使用这个目录,那么很可能会有人输错目录名称,导致报告显示在不同的目录中。这时可以定义一个属性值,由这个属性值指向这个目录。然后,在整个脚本中都可以引用这个属性,这意味着当需要更改的时候,只需光顾一个地方,即属性的定义。清单 7 展示了重构之后的 run-simian 任务:

  清单 7. 使用属性

双击代码全选
 
<target name="run-simian">
 <taskdef resource="simiantask.properties"
  classpath="simian.classpath" classpathref="simian.classpath" />
 <delete dir="${reports.simian.dir}" quiet="true" />
 <mkdir dir="${reports.simian.dir}" />
 <simian threshold="${simian.threshold}" language="${language.type}"
  ignoreCurlyBraces="true" ignoreIdentifierCase="true" ignoreStrings="true"
  ignoreStringCase="true" ignoreNumbers="true" ignoreCharacters="true">
  <fileset dir="${src.dir}"/>
  <formatter type="xml" toFile="${reports.simian.dir}/${simian.log.file}" />
 </simian>
 <xslt taskname="simian"
  in="${reports.simian.dir}/${simian.log.file}"
  out="${reports.simian.dir}/${simian.report.file}"
  style="${config.dir}/${simian.xsl.file}" />
</target>

  硬编码的值不仅没有提高灵活性,反而拟制了灵活性。像在源代码中很容易硬编码数据库连接 String 一样,在构建脚本中也应该避免将路径之类的东西硬编码。

  测试失败时,构建却能成功

  构建远远不止于单纯的源代码编译,它还可能包括自动化开发者测试的执行,如果想让软件一直正常运行,那么决不能允许构建中有任何失败的测试。别忘了,如果测试都得不到信任,那么还要测试干什么呢?

  清单 8 是这种构建气味的一个例子。注意 junit Ant 任务的 haltonfailure 属性被设置为 false(它的缺省值)。这意味着即使任何 JUnit 测试是失败的,构建也不会失败。

  清单 8. 气味:测试失败,构建却成功

双击代码全选

<junit fork="yes" haltonfailure="false" dir="${basedir}" printsummary="yes">
 <classpath refid="test.class.path" />
 <classpath refid="project.class.path"/>
 <formatter type="plain" usefile="true" />
 <formatter type="xml" usefile="true" />
 <batchtest fork="yes" todir="${logs.junit.dir}">
 <fileset dir="${test.unit.dir}">
  <patternset refid="test.sources.pattern"/>
 </fileset>
 </batchtest>
</junit>

  有两种方法防止构建中的这种气味。第一种方法是将 haltonfailure 属性设置为 true。这样可以防止测试失败构建却成功的情况发生。

  对于这种方法,我惟一不喜欢的地方是,我想看看有多大百分比的测试遭到了失败,以便弄清楚失败的模式。因此第二种方法是,每当有测试失败,设置一个属性。然后,我对 Ant 进行配置,使得当执行了所有的测试之后,构建终失败。这两种方法都行之有效。清单 9 演示了使用 tests.failed 属性的第二种方法:

  清单 9. 测试令构建失败

双击代码全选 

<junit dir="${basedir}" haltonfailure="false" printsummary="yes"
 errorProperty="tests.failed" failureproperty="tests.failed">
 <classpath>
  <pathelement location="${classes.dir}" />
 </classpath>
 <batchtest fork="yes" todir="${logs.junit.dir}" unless="testcase">
  <fileset dir="${src.dir}">
   <include name="**/*Test*.java" />
  </fileset>
 </batchtest>
 <formatter type="plain" usefile="true" />
 <formatter type="xml" usefile="true" />
</junit>
<fail if="tests.failed" message="Test(s) failed." />