Maven by Example

4.9. Writing Unit Tests

Maven has built-in support for unit tests, and testing is a part of the default Maven lifecycle. Let’s add some unit tests to our simple weather project. First, let’s create the org.sonatype.mavenbook.weather package under src/test/java:

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

At this point, we will create two unit tests. The first will test the YahooParser, and the second will test the WeatherFormatter. In the weather package, create a file named YahooParserTest.java with the contents shown in the next example.

Simple Weather’s YahooParserTest Unit Test. 

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() );
    }
}

This YahooParserTest extends the TestCase class defined by JUnit. It follows the usual pattern for a JUnit test: a constructor that takes a single String argument that calls the constructor of the superclass, and a series of public methods that begin with “test+” that are invoked as unit tests. We define a single test method, +testParser, which tests the YahooParser by parsing an XML document with known values. The test XML document is named ny-weather.xml and is loaded from the classpath. We’ll add test resources in Section 4.11, “Adding Unit Test Resources”. In our Maven project’s directory layout, the ny-weather.xml file is found in the directory that contains test resources—${basedir}/src/test/resources under' org/sonatype/mavenbook/weather/yahoo/ny-weather.xml'. The file is read as an InputStream and passed to the parse() method on YahooParser. The parse() method returns a Weather object, which is then tested with a series of calls to assertEquals(), a method defined by TestCase.

In the same directory, create a file named WeatherFormatterTest.java.

Simple Weather’s WeatherFormatterTest Unit Test. 

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() );
    }
}

The second unit test in this simple project tests the WeatherFormatter. Like the YahooParserTest, the WeatherFormatterTest also extends JUnit’s TestCase class. The single test function reads the same test resource from ${basedir}/src/test/resources under the org/sonatype/mavenbook/weather/yahoo directory via this unit test’s classpath. We’ll add test resources in Section 4.11, “Adding Unit Test Resources”. WeatherFormatterTest runs this sample input file through the YahooParser which spits out a Weather object, and this object is then formatted with the WeatherFormatter. Since the WeatherFormatter prints out a String, we need to test it against some expected input. Our expected input has been captured in a text file named format-expected.dat which is in the same directory as ny-weather.xml. To compare the test’s output to the expected output, we read this expected output in as an InputStream and use Commons IO’s IOUtils class to convert this file to a String. This String is then compared to the test output using assertEquals().