1 Unit and functional tests
Introduction
Testing performed during the GeoServer build is the first safety net against bugs and regressions
In GeoServer, both of them are performed using JUnit 3.8.x along with a few helper libraries:
- units tests are the lowest level of testing, designed to test the methods of each class. This usually demands some kind of mock objects to replace concrete collaborators, the library chosen to create and make assertions against mock objects is EasyMock
- functional tests do use a mocked up data directory and do startup a full blown GeoServer application context, making tests perform requests similar to those that a user would make. Under cover a web container is mocked up using MockRunner, whilst XML tests against the typical OGC service outputs are performed using either direct DOM checks, or using XPATH with the XMLUnit library.
For any new code written in GeoServer, one should write the corresponding test. Same goes for any fixed bug, a test should be put in place to make sure the bug cannot surface again. There are classes that lack unit tests, but we're serious about getting better at it, so please help us out.
For more information on unit testing see:
- the JUnit site
- http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/default.aspx
- http://blogs.zdnet.com/Burnette/?p=179
Running tests from command line
Each module has a test directory that mirrors the structure of the src directory, put tests for each class in the corresponding package. You can run all units tests by executing the test maven task from the root of a module
[geoserver]% mvn test
| We recommend running unit tests as frequently as possible, and before any commit. |
Functional testing in GeoServer
If at all possible, the first line of defence should be made of standard, isolated unit tests: they are quicker to run and can test a class in ways that a functional test may not exercise.
When unit tests are not possible or not enough, functional tests should be used. GeoServer provides quite an elaborate framework for functional testing that allows for setting up a data directory with fictional data, running requests against the mocked up web container, parsing outputs and checking their validity. The following class diagram depicts the main classes involved in the framework.

Here here a short description of each class in the test hierarchy:
- OneTimeSetupTest: generic test base class for tests that want to perform a "one time setup" and then run all the tests method against the same test fixture, which is supposedly very expensive to create, and won't be modified by the test methods. More on this topic later.
- GeoServerAbstractTestSupport: base class that has the ability to handle a data directory (TestData) and create a GeoServer instance on top of it by loading the Spring context and creating a mock web application in which it will run. It also contains a lot of methods that can be used to perform requests using get/post/put/... methods and get back the results, either as raw streams or as parsed DOM objects.
- GeoServerTestSupport: uses MockData as the test data dir, provides method for subclasses that want to customize the contents of MockData during startup
- KvpRequestReaderTestSupport: adds methods to simplify the testing of a KvpRequestReader
- WMSTestSupport, WFSTestSupport, WCSTestSupport: provide some extra convenience methods for the actual test classes, such as setting up XMLUnit, or providing access to commonly used objects found in the application context.
The TestData hierarchy on the other side is made of:
- TestData: a simple interface representing a data directory, with means to set it up, clean it up, and provide the location of the data directory root
- MockData: a data directory created putting together property files (property data stores) and GeoTiffs. Has a set of built in property files coming from the WFS and WMS cite testing, and provides methods to add/remove those. All of the standard test property files are located in geoserver/data/src/test/java/org/geoserver/data/test.
- LiveData: a mock data directory based on an existing one. Basically it copies the existing one from the classpath into a temp directory, and cleans it up when done
- LiveDbmsData: a subclass of LiveData that assumes one of the datasores is a DBMS. Provides methods to check the local DBMS is available (otherwise tests are skipped), to alter the catalog.xml so that it points to a local DBMS, and to run SQL scripts used to initialize the database structure.
Getting started with testing
Pending a detailed documentation for this, the suggested approach is "monkey see, monkey do". First off, go into the geoserver main module and run mvn javadoc:java.doc, then explore the javadoc for the above classes. Once you've done that, explore ready made tests that are using the capabilities you're interested into:
- MockData based tests with DOM based checks: WFS GetFeatureTest
- MockData based tests with XMLUnit based checks: WCS 1.1 GetCapabilities test
- MockData based tests that does customize feature types being used (adds a new feature type): WFS ReprojectionTest
- MockData based tests that do customize the coverage being added, and makes sure no feature types are there too: WCS test support
- LiveDbmsData based test: WFSV base test class along with the necessary resources
Test setup and teardown with GeoServerAbstractTestSupport
The testing base class allows for for per method and per test setup and teardown. In order to do so it inherits from OneTimeTestSetup and changes a little bit the rules you have to follow to setup a test:
- in order to set up and tear down a per method test fixture, you have to override the setUpInternal and tearDownInternal methods (the setUp and tearDown methos are declared final in OneTimeTestSetup) and store the test fixture in standard test class fields
- in order to set up and tear down a per class test fixture, you have to override the oneTimeSetUp and oneTimeTearDown methods and store the test fixture in static fields of the test class.
Overriding oneTimeSetUp and oneTimeTearDown methods is not necessary, if the test does not need them it can safely ignore them. Yet, the creation of a mock data directory is an expensive process, so if the test does not alter its contents, it makes sense to create it just once and use it for all the tests methods.
In order to have a test use "one time set up" you don't necessarily have to override the oneTimeSetUp/oneTimeTearDown methods (do so only if your class needs some extra one time fixtures beside the data dir), but it's required that you add a static suite() method as follows:
public MyTestClass extends GeoServerTestSupport { ... /** * This is a READ ONLY TEST so we can use one time setup */ public static Test suite() { return new OneTimeTestSetup(new MyTestClass()); } ... }
You'll notice the effect immediately: when running the tests, the first one will take the usual time, the other will fly by in an instant.
Some examples:
- a test class that just enables one time setup: WFS GetFeatureTest
- a test class that enables one time setup and has its own extra one time fixture: WMS FeatureTimeTemplateTest
- a test class that does not uses one time setup because it's modifying the data dir contents: WFS TransactionTest
When implementing test classes based on GeoServerAbstractTestSupport (or its subclasses) pay attention to the following caveats:
- when overriding setUpInternal(), make sure you call super.setUpInternal(), not super.setUp(), nor super.oneTimeSetUp() (same goes for tearDownInternal)
- when overriding oneTimeSetUp() make sure super.oneTimeSetUp() is called, otherwise the mock data dir won't be created (same goes for oneTimeTearDown()