My favorites | Sign in
Project Logo
                
Search
for
Updated Feb 18, 2009 by adam.christian
Labels: Featured
MozMillTestBasics  
Test Writing Basics

Basic Test Template

var mozmill = {}; Components.utils.import('resource://mozmill/modules/mozmill.js', mozmill);
var elementslib = {}; Components.utils.import('resource://mozmill/modules/elementslib.js', elementslib);

var setupModule = function(module) {
  module.controller = mozmill.getBrowserController();
}

var testFoo = function(){
  controller.open('http://www.google.com');
}

Explained

First you import two very important test resources. One is the main mozmill module, it contains a series of convenience functions and references to other modules you'll need for writing tests. The second is elementslib which is the library mozmill uses for abstracting interface nodes to be used by mozmill controllers.

The way the mozmill framework works is to imports a test file as a test module. Then it runs setupModule if it's been declared, passing in the module itself as an argument.

The test framework then runs any test functions with names that begin with test.

If you have resources that need to be declared for your entire test file it's very important that you do so in setupModule. When running multiple test files together all the files get parsed in as modules before any tests are run, which means if you have shared resources that do things in the application (creating any controller will open that window, for example) and they are just declared in the base of the module they will all run at once before any tests run.

Using Dependencies

The MozMill test framework supports a very simple yet powerful dependency system. The idea is simple, a test can refer to a relative root path on the filesystem. Any other test modules a test might require will be in that path or in a subdirectory that starts with "test". When that test is parsed, the directory tree is recursively parsed and all javascript files and directories that begin with "test" are imported.

Since it's common for two files in different directories to have the same name you must name your module using the MODULE_NAME variable if you want other test modules to have access to it or depend on it in related test modules. Other tests can then depend on that test module using it's name and all it's setup/teardown and tests will be run before any of it's dependents. Other tests can also access dependent test modules by name.

Example:

tests/test_parent.js

var MODULE_NAME = 'test_parent';

var getString = function() { return 'asdf' };

var testStub = function() {};

tests/test_sub/test_deps.js

var jum = {}; Components.utils.import('resource://mozmill/modules/jum.js', jum);

var RELATIVE_ROOT = '..';

var MODULE_REQUIRES = ['test_parent'];

var setupModule = function(module) {
  module.stringTest = module.collector.getModule('test_parent').getString();
}

var testDependencies = function() {
  jum.assertEquals(stringTest, 'asdf');
}

Explained

test_parent.js declares a name for it's module so that other modules can depend on it.

test_deps.js is in a directory below test_parent.js so test_deps.js declares a RELATIVE_ROOT to the parent directory.

Since test_deps.js depends on test_parent.js all the setup/teardown and test functions in test_parent.js will get run before test_deps.js even if only test_deps.js is passed to the mozmill runner. This means that testStub will get run before testDependencies in this scenario.

As you can see in test_deps.js/setupModule each module's collector object is attached to the module after it's been imported. The collector has hashes of all the modules that have been imported so you can get a module out by name by using the collector's getModule method.

Serving local test files

In many cases you'll need to serve local web pages and javascript for a given test. Rather than have to deal with setting up and tearing down an HTTP server mozmill offers a way for you to serve out local files relative to your test the same way you can declare dependencies relative to your test.

var mozmill = {}; Components.utils.import('resource://mozmill/modules/mozmill.js', mozmill);
var elementslib = {}; Components.utils.import('resource://mozmill/modules/elementslib.js', elementslib);

var url = collector.addHttpResource('./files');

var setupModule = function(module) {
  module.controller = mozmill.getBrowserController();
}

var testFoo = function(){
  controller.open(url+'index.html');
}

This exposes a nice little bit of the test framework internals. The collector is responsible for importing tests and modules. The collector is actually available in the space your test is evaluated in and since it knows which file it's currently importing it also knows how to get to any file path relative to the current test.

In the above example url will be a variable like http://localhost:43336/a76s67dtf76s6gdgs/. By default this function will serve the files in a namespace it generates. If you would like to serve your files in a cleaner namespace you can send it as another argument.

var url = collector.addHttpResource('./files', 'myNamespace');

This way url will be something like http://localhost:43336/myNamespace. The port configuration is handled for you and mozmill is smart enough to always find an open local port to serve the files up on.



Sign in to add a comment
Hosted by Google Code