Added by Jive, last edited by Cory Horner on Jul 05, 2007  (view change)

Labels:

pending pending Delete
Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.

As you code, you should write a unit test for each class to test the functionality and robustness of the class. This is made much easier by using JUnit.
JUnit is very good at:

  • capturing a Jira bug report in a reproducable manner
  • allowing you to specify exactly the behaviour your want - before you start coding
  • unit testing

The general idea:

  • If you are testing src/org/geotools/module/HelloWorld.java
  • create a file test/org/geotools/module/HelloWorldTest.java
  • any public void methods starting with test will be run by JUnit
  • maven will run all tests for your module using: mvn test
    tests can be ignored using you pom.xml file
  • maven will not "release" your module into the repository while it still fails unit testing
Code Coverage vs Regression Testing

Code Coverage reports are available via:

mvn site

The percentage reported is based on the lines of code your test cases manage to test, please limit this to "real" tests - although we demand 60% test coverage for supported modules we would much rather this is produced honestly.

Creating boiler plate tests that just call assertEquals against every method, and cutting and pasting the current result is an example of a regression test. While this will catch changes in our codebase it is not nearly as useful as actually testing for what you expect.

Use of Maven Test Profiles

pending review

You can also make use of maven profiles to isolate long running tests from the day to day grind of other GeoTools developers.

Install with all normal tests:

mvn install

Install with online tests (will connect to servers around the world):

mvn -P online install

Install with stress tests (long running tests that try to break the code using many threads):

mvn -P stress install

You can combine profiles as needed:

mvn -P online,stress install

To keep build times down (so tests are run at all) we ask you to stay in the following time limits.

20 seconds for a module
5 seconds for a plugin
5 seconds for an ext

Tests on unsupported modules are not subject to a time limit, to run your tests in an unsupported module you will need to make use of the provided profile:

mvn -P unsupported install

Example TestCase

package org.geotools.module;

import org.geotools.map.BoundingBox;

/**
 * Unit test for BoundingBox.
 *
 * @author Cameron Shorter
 */
public class HelloWorldTest extends TestCase {

    /** Test suite for this test case */
    private TestSuite suite = null;

    /**
     * Constructor with test name.
     */
    public HelloWorldTest(String testName) {
        super(testName);
    }

    /**
     * Main for test runner.
     */
    public static void main(String[] args) {
        junit.textui.TestRunner.run(suite());
    }

    /**
     * Required suite builder.
     * @return A test suite for this unit test.
     */
    public static Test suite() {
        TestSuite suite = new TestSuite(HelloWorldTest.class);
        return suite;
    }

    /**
     * Initialize variables
     */
    protected void setUp() {
        // initialize variables
    }

    /** Test normal constuctors. */
    public void testHello(){
        assertTrue("HelloWorld should return null is true",HelloWorld.isNull());
    }
}

Testing with junit is as easy as copying HelloWorldTest.java and adding more tests, and then executing it. If you want more information, look at the junit documentation or read one of the many junit tutorials.

Online Tests

We make use of a naming convention, ie ensure the name of your TestCase ends in OnlineTest, to indicate the use of external web services and databases.

These tests will be skipped as part of the normal build process, but will be executed by certain build boxes and .

In addition to the naming convention, such tests should extend the OnlineTestCase class, since it will extract connection parameters from fixture properties files in the user's ~/.geotools directory with minimal hassle. Test cases extending this class will need to implement the getFixtureId() method which will return the identifier for a fixture; a fixture id of "postgis.typical" will attempt to read the file "~/.geotools/postgis/typical.properties".

Each module should try to provide default fixture files pointing to publicly accessible servers. Users running online tests will copy these defaults and customize them accordingly. If a fixture file is missing, its tests will not be run; therefore, if one deletes the ~/.geotools/oracle directory, for example, all oracle online tests will be disabled.

For more details see: Online Test Fixtures, which defines the identity of each fixture and what its expected qualities and contents are.

Example Use

Example use (using PostgisOnlineTestCase):

public abstract class PostgisOnlineTestCase extends OnlineTestCase {
    protected DataStore dataStore;

    protected abstract String getFixtureId();

    protected void connect() throws Exception {
        Map params = getParams();
        dataStore = new PostgisDataStoreFactory().createDataStore(params);
    }
    
    public Map getParams() {
        Map params = new HashMap();

        params.put(PostgisDataStoreFactory.DBTYPE.key, "postgis");
        params.put(PostgisDataStoreFactory.HOST.key, fixture.getProperty("host"));
        params.put(PostgisDataStoreFactory.PORT.key, fixture.getProperty("port"));
        params.put(PostgisDataStoreFactory.SCHEMA.key, fixture.getProperty("schema"));
        params.put(PostgisDataStoreFactory.DATABASE.key, fixture.getProperty("database"));
        params.put(PostgisDataStoreFactory.USER.key, fixture.getProperty("user"));
        params.put(PostgisDataStoreFactory.PASSWD.key, fixture.getProperty("password"));

        if (fixture.containsKey("wkbEnabled")) {
            params.put(PostgisDataStoreFactory.WKBENABLED.key, fixture.getProperty("wkbEnabled"));
        }
        if (fixture.containsKey("looseBbox")) {
            params.put(PostgisDataStoreFactory.LOOSEBBOX.key, fixture.getProperty("looseBbox"));
        }
        return params;
    }
    protected void disconnect() throws Exception {
        dataStore = null;
    }
}

Example LocalPostgisOnlineTest

And here is a sample use:

class LocalPostgisOnlineTest extends PostgisOnlineTestCase  {
    protected abstract String getFixtureId(){
        return "local";
    }
}

As a rule of thumb, online tests should not fail if a server is unavailable.

Example Fixture

Example fixture ~/.geotools/postgis/local.properties:

host=localhost
port=15234
schema=bc
user=postgres
passwd=postgres
database=bc
wkbEnabled=true

In windows you cannot create a ".geotools" folder!

  1. Open up a CMD window
  2. cd to your home directory and use mkdir
    C:\Documents and Settings\Fred>mkdir .geotools
  3. And set up any fixtures you need:
    C:\Documents and Settings\Fred>cd .geotools
    C:\Documents and Settings\Fred\.geotools>mkdir postgis
    C:\Documents and Settings\Fred\.geotools>cd postgis
    C:\Documents and Settings\Fred\.geotools\postgis>notepad typical.properties
    # And use the [default fixture files|http://svn.geotools.org/geotools/trunk/gt/build/fixtures/] as a guide

Examples:
PostgisOnlineTestCase - Abstract Testcase class which connects to a specified database and creates a datastore
PostgisPermissionOnlineTest - Simple online test which makes use of PostgisOnlineTestCase