MapScript Unit Testing

Date

2005-11-20

Author

Sean Gillies

Note

The msautotest infrastructure is recommended, as it is run for each commit/pull request to the MapServer repository.

Test Driven Development

In 2003, I began to commit to test driven development of the mapscript module. TDD simply means development through repetition of two activities:

  1. add a test, cause failure, and write code to pass the test

  2. remove duplication

Test Driven Development is also a book by Kent Beck.

New features that I develop for MapServer begin as test expressions. There are a bazillion good reasons for working this way. The most obvious are

  1. accumulation of automated unit tests

  2. accumulation of excellent usage examples

  3. that i’m prevented from starting work on flaky ideas that can’t be tested

About the tests

Tests are committed to the MapServer CVS under mapscript/python/tests. They are written in Python using the JUnit inspired unittest module. A good introduction to unit testing with Python is found at http://diveintopython.org/unit_testing/index.html.

The test framework imports mapscript from python/tests/cases/testing.py. This allows us to test the module before installation

[sean@lenny python]$ python setup.py build
[sean@lenny python]$ python tests/runtests.py -v

Test cases are implemented as Python classes, and individual tests as class methods named beginning with test*. The special setUp() and tearDown() methods are for test fixtures and are called before and after every individual test.

Since version 4.2, MapServer includes a very lightweight testing dataset under mapserver/tests. The set consists of symbols, fonts, three single-feature shapefiles, and a test.map mapfile. This is the only data used by the unit tests.

Many tests that require a mapObj derive from testing.MapTestCase:

class MapTestCase(MapPrimitivesTestCase):
    """Base class for testing with a map fixture"""
    def setUp(self):
        self.map = mapscript.mapObj(TESTMAPFILE)
    def tearDown(self):
        self.map = None

One example is the MapSymbolSetTestCase, the test case I used for development of the expanded symbolset functionality present in the 4.2 release:

class MapSymbolSetTestCase(MapTestCase):
    def testGetNumSymbols(self):
        """expect getNumSymbols == 2 from test fixture test.map"""
        num = self.map.getNumSymbols()
        assert num == 2, num

    ...

Status

This unit testing framework only covers functionality that is exposed to the Python mapscript module. It can help to check on pieces of the core MapServer code, but is no guarantor of the mapserv program or of the PHP MapScript module. As of this writing, there are 159 tests in the suite. These are tests of features added since mid-2003. Much of MapServer’s older stuff remains untested and it is doubtful that we’ll make the time to go back and fill in.