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

发表于:2013-03-04来源:IBM作者:Paul Duvall点击数: 标签:持续测试
让开发过程自动化:做好持续测试! 准备好开始在您的开发人员测试活动中大获全胜吗?在本期的 让开发自动化 中,开发自动化专家 Paul Duvall 介绍了几种自动化的开发人员测试,每一次改变源代码都能够运行这些测试。Paul 提供了 Selenium、DbUnit 和 JUnitPerf 测试的例

  在像 Eclipse 那样的 IDE 中或者比如在 Ant 构建脚本中运行单元测试是确保应用程序质量的一个很好的开始;然而,版本控制库(如 Subversion)中的源代码一改变,在单独无变动的构建机上运行单元测试就有助于检验开发生命周期中的问题。而且,运行各种类型的开发人员测试,如组件测试、功能测试性能测试,能够在开发生命周期中更早地 将问题显示出来。

  关于本系列

  作为开发人员,我们的工作就是为终端用户实现过程自动化;然而,很多开发人员却忽略了将自己的开发过程自动化的机会。为此,我编写了 让开发自动化 这个系列的文章,专门探讨软件开发过程自动化的实际应用,并教您何时 以及如何 成功地应用自动化。

  通常在持续集成(CI)环境中运行的开发人员测试有效地扮演着代码质量聚光灯的角色。这是因为如果能有效地编写这些测试,则几乎能够在问题(如缺陷)产生之时就将其发现。不经常运行测试通常就不怎么有效,因为从产生缺陷到发现该缺陷的时间相隔很长,但持续地(即,每一次代码改变时)运行测试能确保快速发现无意识的行为。

  本文涵盖下列内容:

  通过 Ant 运行 JUnit 测试

  使用 JUnit 和 DbUnit 执行更长时间的运行组件测试

  使用 JUnitPerf 确定哪些方法花费时间过久而执行失败

  用 Selenium 运行基于 Web 的功能测试

  用 Cobertura 访问代码覆盖率

  用 CruiseControl 进行持续测试

  我提供一个关于不同类型开发人员测试的概览,和一些可以添加到构建过程并使用 Continuous Integration 系统持续运行的例子。

  按 JUnit 进行单元测试

  有人称之为单元测试,有人称之为组件测试

  经常提到的单元测试其实更像是一个组件级别的测试。组件测试通常验证不止一个类,并且依赖于一些东西,如数据库或其他重量级系统,如文件系统。但是更重要的是,在测试的基础上进行测试,组件测试比单元测试运行时间更长。

  有时,我听到开发人员将开发人员测试这一术语与简单的单元测试相混淆;然而,我发现将单元测试这一术语提练得更加明确很有帮助。对我来说,单元测试是快速运行的 测试,通常测试没有大的外部依赖项(如数据库)的单独的类。例如,清单 1 定义了一个单元测试,该测试使用 JUnit 来验证一个叫做 BeerDaoStub 的存根数据类。针对并未真正连接到数据库的接口的测试技术是一种验证业务功能的方法,使用该方法不会导致花费昂贵的设置成本。另外,这样做可使测试保持为一个真正的单元测试。

  清单 1. 一个简单的单元测试

public void setUp() {
  beerService = new BeerDaoStub();
}

public void testUnitGetBeer() {
  Collection beers = beerService.findAll();
  assertTrue(beers != null && beers.size() > 0);
}

  一旦编写了一些单元测试,就可以一直通过 IDE 运行这些测试,但您也想要将这些测试作为构建过程的一部分来运行。确保该测试通过构建过程成功运行意味着也能从 CI 构建的上下文中启动这些相同的测试。

  清单 2 是一个 Ant 脚本片段,介绍了执行一批单元测试的 junit 任务。这项任务与 JUnit 一起运作,其妙处在于:定义过的所有测试现在都能自动运行并且如果其中任何一个测试失败,则构建也将失败 —— 通过使用 haltonfailure 属性实现。

  清单 2. 在 Ant 中运行单元测试

<junit fork="yes" haltonfailure="true" 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>  

  注意:test.unit.dir 指定测试的位置。这是将这些测试(在本例中为单元测试)和其他测试隔离起来的有效方法。通过利用这项技术,可以通过定义另外的 Ant 目标来先运行较快的测试,接着运行较慢的测试(如组件测试、功能测试和系统测试)。

  回页首

  集合组件测试

  由于单元测试执行得相当快,很容易将它们作为构建的一部分经常运行。但这些测试并未达到一个高的代码覆盖率 —— 其隔离的本质决定了它们只测试一部分功能。编写具有更多代码(从而可实现更多功能)的测试通常要以附属框架的形式执行更多的调查工作。一旦开始使用这些帮助框架来编写测试,这些测试就开始成为更高级别的测试,我把它们归类为组件测试。

  组件测试是基本的测试,这些测试将验证不止一个类,且通常依赖于外部依赖项,如数据库。组件测试的编写方式和单元测试大体一致,只是前者并非通过模拟或存根类来强制隔离,实现这些测试可谓勉为其难,但可以利用框架来便利对外部依赖项的使用。例如,我通常使用 DbUnit 框架来帮助管理数据库,以便组件测试可验证依赖数据库数据的代码功能。

  用 DbUnit 控制数据库状态

  DbUnit 是一个框架,它使针对数据库的测试过程变得更加简单。它提供了一个标准 XML 格式,用于定义一些测试数据,以便从数据库中选择、更新、插入和删除数据。请牢记,DbUnit 并没有替换数据库;它只是提供了一种更加有效的机制来处理测试数据。您可以用 DbUnit 来编写依赖于特定数据的测试,DbUnit 保证该数据位于底层的数据库中。

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