4.9. 编写单元测试

Maven 内建了对单元测试的支持,测试是 Maven 默认生命周期的一部分。让我们给 Simple Weather 项目添加一些单元测试。 首先,在 src/test/java 下面创建包 org.sonatype.mavenbook.weather

$ cd src/test/java
$ cd org/sonatype/mavenbook
$ mkdir -p weather/yahoo
$ cd weather/yahoo

目前,我们将会创建两个单元测试。 第一个单元测试会测试 YahooParser ,第二个会测试 WeatherFormatter。 在 weather 包中,创建一个带有一以下内容的文件,名称为 YahooParserTest.java

Example 4.11. Simple Weather 的 YahooParserTest 单元测试

package org.sonatype.mavenbook.weather.yahoo;

import java.io.InputStream;

import junit.framework.TestCase;

import org.sonatype.mavenbook.weather.Weather;
import org.sonatype.mavenbook.weather.YahooParser;

public class YahooParserTest extends TestCase {

  public YahooParserTest(String name) {
    super(name);
  }
 
  public void testParser() throws Exception {
    InputStream nyData = 
      getClass().getClassLoader().getResourceAsStream("ny-weather.xml");
    Weather weather = new YahooParser().parse( nyData );
    assertEquals( "New York", weather.getCity() );
    assertEquals( "NY", weather.getRegion() );
    assertEquals( "US", weather.getCountry() );
    assertEquals( "39", weather.getTemp() );
    assertEquals( "Fair", weather.getCondition() );
    assertEquals( "39", weather.getChill() );
    assertEquals( "67", weather.getHumidity() );
  }
}

YahooParserTest 继承了 JUnit 定义的 TestCase 类。 它遵循了 JUnit 测试的惯例模式:一个构造函数接受一个单独的 String 参数并调用父类的构造函数,还有一系列以“test”开头的公有方法,做为单元测试被调用。 我们定义了一个单独的测试方法, testParser ,通过解析一个值已知的 XML 文档来测试 YahooParser 。 测试 XML 文档命名为 ny-weather.xml ,从 classpath 载入。我们将在Section 4.11, “添加单元测试资源”添加测试资源。 在我们这个 Maven 项目的目录布局中,文件 ny-weather.xml 可以从包含测试资源的目录—— /data/hudson-temporal-data/hudson-orchestrator-home/workspace/Book-To-Production/content-zh/src/test/resources ——中找到,路径为 org/sonatype/mavenbook/weather/yahoo/ny-weather.xml 。 该文件作为一个 InputStream 被读入,传给 YahooParserparse() 方法。 parse() 方法返回一个 Weather 对象,该对象通过一系列 由 TestCase 定义的 assertEquals() 调用而被测试。

在同一目录下创建一个名为 WeatherFormatterTest.java 的文件。

Example 4.12. Simple Weather 的 WeatherFormatterTest 单元测试

package org.sonatype.mavenbook.weather.yahoo;

import java.io.InputStream;

import org.apache.commons.io.IOUtils;

import org.sonatype.mavenbook.weather.Weather;
import org.sonatype.mavenbook.weather.WeatherFormatter;
import org.sonatype.mavenbook.weather.YahooParser;

import junit.framework.TestCase;

public class WeatherFormatterTest extends TestCase {

  public WeatherFormatterTest(String name) {
    super(name);
  }

  public void testFormat() throws Exception {
    InputStream nyData = 
      getClass().getClassLoader().getResourceAsStream("ny-weather.xml");
    Weather weather = new YahooParser().parse( nyData );
    String formattedResult = new WeatherFormatter().format( weather );
    InputStream expected = 
      getClass().getClassLoader().getResourceAsStream("format-expected.dat");
    assertEquals( IOUtils.toString( expected ).trim(), formattedResult.trim() );
  }
}

该项目中的第二个单元测试测试 WeatherFormatter。 和 YahooParserTest 一样,WeatherFormatter 同样也继承 JUnit 的 TestCase 类。 这个单独的测试通过单元测试的 classpath 从 /data/hudson-temporal-data/hudson-orchestrator-home/workspace/Book-To-Production/content-zh/src/test/resourcesorg/sonatype/mavenbook/weather/yahoo 目录读取同样的测试资源文件。 我们将会在Section 4.11, “添加单元测试资源”添加测试资源。 WeatherFormatterTest 首先调用 YahooParser 解析出 Weather 对象,然后用 WeatherFormatter 格式化这个对象。 我们的期望输出被存储在一个名为 format-expected.dat 的文件中,该文件存放在和 ny-weather.xml 同样的目录中。 要比较测试输出和期望输出,我们将期望输出作为 InputStream 读入,然后使用 Commons IO 的 IOUtils 类来把文件转化为 String 。 然后使用 assertEquals() 比较这个 String 和测试输出。