OpenLayers OpenLayers

OpenLayers uses the Test.AnotherWay framework for unit testing. This testing framework is designed to run in a browser: you can run the tests against SVN to see how they work.

Writing tests is simple, and creating an entirely new test file requires three steps:

Create an HTML file

First, create an HTML file. Because testing is carried out in the tests/ dir of OpenLayers, it should reference ../lib/OpenLayers.js to load code. An example HTML file looks like this:

<html>
<head>
  <script src="../lib/OpenLayers.js"></script>
  <script type="text/javascript">
    var map; 
  </script>
</head>
<body>
    <div id="map" style="width: 1080px; height: 600px;"/>
</body>
</html>

This page should contain any elements you need to run your test.

Adding test functions

The next step is to add functions which are your 'tests'. Any function which begins with the string 'test_' is run by the testing framework. One argument is passed to these functions: that argument is a 'testing' object which you can use to assert certain things. A simple testing function might look like this:

function test_Map_Zoom(t) {
    t.plan(1);
    var map = new OpenLayers.Map("map");
    var layer = new OpenLayers.Layer.WMS("ABC", "http://example.com/123", {'layers':'test'});
    map.addLayer(layer);
    map.zoomTo(0);
    t.eq(map.zoom, 0, "Zoomed to level 0 correctly.");
}

The first line is the test plan. This is how many tests you expect to succeed. The next four lines set up a simple map object, and the last line uses t.eq() to test equivilance of two variables.

Other test methods are:

  • t.ok(boolean, "String for output")
  • t.like(value, regex, "String for output")
  • t.html_eq(DOM Element, HTML expected, "String for output")

For more information on how to write asynchronous tests and the like, see the Test.AnotherWay docs.

Add your tests to the testing plan

The last step is to edit list-tests.html in the tests/ directory to run your tests.

That's it! Open run-tests.html, and you can choose to run just the test file you created, or you can choose to run all tests.

Modifications to Test.AnotherWay

The Test.AnotherWay code has been modified in a number of ways to better suit our needs.

Testing XML Equivalence

Test objects have been extended to include an xml_eq method. The run-tests.html page includes the xml_eq.js script to get this functionality. With the xml_eq method you can compare element nodes to element nodes, xml strings to nodes, or strings to strings.

The xml_eq method takes three arguments (and an optional fourth):

  • got - {DOMElement|String} The element node (type 1 node) or xml string you are testing.
  • expected - {DOMElement|String} The element node or xml string you expect.
  • msg - {String} Message for test output.
  • options - {Object} Optional object for configuring the tests. Setting options.prefix to true causes namespace prefixes (aliases) to be compared as well. Without this option, namespace URI are always tested. By default, nodes with the same namespace URI but different prefixes are considered equivalent.

A test function on a test page might look something like the following:

function test_soup(t) {

    t.plan(4);
    var format = new OpenLayers.Format.XML();
    var doc, got, exp;
    
    // Create a doc and check that root is equivalent to some string
    doc = format.read(
         "<chicken>soup</chicken>"
    );
    got = doc.documentElement;
    exp = "<chicken>soup</chicken>";
    t.xml_eq(got, exp, "passes");
    
    // See what happens with bad expectations
    exp = "<chicken>fat</chicken>";
    t.xml_eq(got, exp, "fails");
    // Fails with the following message:
    // Bad child 0 for element chicken: Node value mismatch: got soup
    // but expected fat
    
    // Test xml with different namespace aliases
    got = "<foo:chicken xmlns:foo='namespace'>soup</foo:chicken>";
    exp = "<bar:chicken xmlns:bar='namespace'>soup</bar:chicken>";
    t.xml_eq(got, exp, "passes");
    
    // Assert that prefixes are equal
    t.xml_eq(got, exp, "fails", {prefix: true});
    // Fails with the following message:
    // Node name mismatch: got foo:chicken but expected bar:chicken

}