硬编码的值不仅没有提高灵活性,反而拟制了灵活性。像在源代码中很容易硬编码数据库连接 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." />