让开发过程自动化:做好持续测试(4)

发表于:2013-03-04来源:IBM作者:Paul Duvall点击数: 标签:持续测试
执行 Selenium 测试时,当框架打开 Web 浏览器、闪电般执行测试,然后关闭该浏览器并生成 HTML 报告时,不要被吓到。这是一种在开发生命周期的早期更快更

  执行 Selenium 测试时,当框架打开 Web 浏览器、闪电般执行测试,然后关闭该浏览器并生成 HTML 报告时,不要被吓到。这是一种在开发生命周期的早期更快更容易地发现问题的方法(此时它们更易处理)。

  回页首

  使用 Cobertura 报告代码覆盖率

  是否达到 100% 就是问题所在

  运行像 Cobertura 或者 Emma 这样的工具时,记住以下方面很重要:在一个特殊的方法中实现 100% 的行覆盖并不意味着该方法没有缺陷或者它已被完全测试。例如,如果您编写了一个针对 if 语句的测试,该测试包含逻辑 And,而测试针对的是表达式的左侧部分,则像 Cobertura 这样的工具将报告 100% 行覆盖,但是实际上,您仅执行了该语句的 50%;因此仅完成了 50% 的分支覆盖。

  现在已经编写了一些测试,如何确定所有这些测试执行什么 呢?幸运的是,此问题可由像 Cobertura 这样的代码覆盖工具来解答。代码覆盖工具可报告测试覆盖率 —— 以行覆盖或分支覆盖形式表示 —— 它表示测试运行时所涉及的代码量。

  清单 8 展示了一个 Ant 脚本。该脚本使用 Cobertura 生成一份关于代码覆盖率的 HTML 报告,代码覆盖率通过运行一系列 JUnit 测试获得:

  清单 8. 使用 Ant 和 Cobertura 报告代码覆盖率

<target name="instrument-classes">
  <mkdir dir="${instrumented.dir}" />
  <delete file="cobertura.ser" />
  <cobertura-instrument todir="${instrumented.dir}">
    <ignore regex="org.apache.log4j.*" />
    <fileset dir="${classes.dir}">
      <include name="**/*.class" />
      <exclude name="**/*Test.class" />
    </fileset>
  </cobertura-instrument>
</target>

<target name="run-instrumented-tests" depends="instrument-classes">
  <mkdir dir="${logs.junit.dir}" />
  <junit fork="yes" haltonfailure="true" dir="${basedir}" printsummary="yes">
    <sysproperty key="net.sourceforge.cobertura.datafile" file="cobertura.ser" />
    <classpath location="${instrumented.dir}" />
    <classpath location="${classes.dir}" />
    <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.component.dir}">
	    <patternset refid="test.sources.pattern"/>
      </fileset>
    </batchtest>
  </junit>
</target>

  Cobertura 产生了一个如图 1 中所示的 HTML 报告。请注意行覆盖和分支覆盖的百分比是以包计算的。可单击每一个包,获得类级别的行百分比和路径百分比,甚至能看到执行的源代码行和它们执行的次数。

  图 1. 使用 Cobertura 和 Ant 生成 HTML 报告

 使用 Cobertura 和 Ant 生成 HTML 报告

  需要多高的代码覆盖率?

  理想情况下,您可能想针对每个路径执行一次测试。也就是说,如果整个代码基址有 20,000 的循环复杂度的话,则需要 20,000 次测试。我从未遇到过具有 100% 的路径覆盖的项目,不过我曾见过具有近 100% 的行覆盖的团队。

  已经介绍了多种类型的测试,甚至介绍了如何测量这些测试的覆盖率 —— 但是如何确保以正常的间隔执行 这些测试呢?恰好,这正是 CI 服务器(如 CruiseControl)大显身手的地方,接下来对它进行介绍。

  持续运行测试

  一旦将这些各式各样的开发人员测试类型合并到一个构建过程中时,可以将这些测试中的一些(或者全部)作为 CI 过程的一部分运行。例如,清单 9 是 CruiseControl 的 config.xml 文件的一个片段,我在其中定义了一些东西。首先,我让 CruiseControl 每两分钟监控一次 Subversion 库中的改变。如果发现任何改变,则 CruiseControl 将启动一个叫做 build-${project.name}.xml 的委托 构建脚本(通常,此脚本用 Ant 编写)。该委托构建脚本调用项目的构建脚本,后者执行编译并运行测试。

  我也定义了一些逻辑,将所有不同类型的测试结果合并到一个 CruiseControl 日志文件中。而且,我还利用 CruiseControl 的功能将不同工具生成的报告链接(使用 artifactspublisher 标签)到 Build Artifacts 链接中,Build Artifacts 可以从 CruiseControl 的显示板应用程序中获得。

  清单 9. 使用 CruiseControl 的 CI

...
<modificationset quietperiod="30">
  <svn RepositoryLocation="http://your-domain.com/trunk/brewery"
    username="bfranklin"
    password="G0Fly@Kite"/>
</modificationset>
<schedule interval="120">
  <ant anthome="apache-ant-1.6.5" buildfile="build-${project.name}.xml"/>
</schedule>
<log dir="logs/${project.name}">
  <merge dir="projects/${project.name}/_reports/unit"/>
  <merge dir="projects/${project.name}/_reports/component"/>
  <merge dir="projects/${project.name}/_reports/performance"/>
  <merge dir="projects/${project.name}/_reports/functional"/>
  <merge dir="projects/${project.name}/_reports/coverage"/>
</log>
<publishers>
  <artifactspublisher 
    dir="projects/${project.name}/_reports/" 
    dest="projects/artifacts/${project.name}"/>
</publishers>
...

原文转自:http://www.ibm.com/developerworks/cn/java/j-ap03137/index.html