Lightest Documentation

This documentation provides some useful reference material related to using Lightest. For a more hands-on reference, try the Lightest tutorial!

What Is Lightest?

Lightest is a task-oriented functional and integration test automation framework built on Groovy and TestNG. It's a "framework framework" that is intended to greatly simplify the process of creating your own custom framework by implementing the testcase management, execution, and reporting for you - all you do is define the test environment and write the tasks!

You might want to try Lightest if:

The Lightest project is hosted on Google Code. You may download releases, browse the source, or file issues there.

Running Lightest

The Lightest framework comes with a runner packaged in an executable JAR. The standalone distribution includes all required dependencies; no external libraries are needed. Tests are run from the command line by specifying a configuration file (see below for syntax) and either a list of Groovy test files (which subclass LightestTestCase, also see below) or a TestNG suite XML file which specifies the test classes and groups to run. The most important configuration to get right is the classPaths element; most other configurations have sensible defaults.

$ java -jar lightest-core-0.2-standalone.jar config.txt MyTest.groovy MyTest2.groovy
$ java -jar lightest-core-0.2-standalone.jar config.txt testng.xml

You can start the runner in interactive mode by providing the right switch:

$ java -jar lightest-core-0.2-standalone.jar --interactive config.txt MyTest.groovy

Lightest requires at least Java 1.5 . Surprisingly, you shouldn't need to install Groovy on your machine to run Lightest. However, you'll probably want to have a reasonably recent version (1.5.4 or later) to use when developing your tasks. If you don't have it, get it here!

The runner produces an HTML report, which in turn is generated from an XML report. HTML is probably the most convenient reporting format; however, it is possible to customize Lightest to create reports in other formats. See the tutorial for screenshots of the reports that are produced.

Configuration File Reference

The configuration file specified as the first argument to the runner follows a Groovy builder syntax, with the config element as its root node.

Element Description Example
classPaths

Contains path elements which enumerate the class paths that should be used to locate task, testcase, preference, and environment classes. By default, the current directory . is included in the path. There is no limit to the number of entries.

You will probably get an error if any class specified in a configuration cannot be loaded from the class paths set here.

config {
...
    classPaths {
        path ('/path/to/tasks')
        path ('../path/to/tests')
    }
...
}
outputDir Specifies the report output directory. The report files will be placed directly in this directory. If unspecified, by default the report will be created in the lightest-report directory in the directory where the test runner was invoked. If more than one directory is specified, only the first entry will be used.
config {
...
    outputDir ('/path/to/report')
...
}
prefs Specifies name-value pairs for preferences to be shared across all tests being configured in this run. The preferences must have a corresponding class, which has publicly-accessible properties to match the preference names. There should be only one prefs element.
config {
...
    prefs (class: 'my.package.Preferences') {
        timeout (5000)
        corpus ('main')
    }
...
}
envs

Enumerates test environments that are available to the tests being configured in this run. Tests may be run concurrently across these environments.

All environments correspond to a single class, but have name-value pairs which may differentiate them. Testcases and tasks are able to access these values for the purpose of interacting with their respective environment. These name-value pairs must match properties of the environment class. Each environment must have a unique String identifier.

There should be only one envs element. If none are specified, 3 default environments identified by unspecified1, unspecified2, and unspecified3 will be provided.

config {
...
    envs (class: 'my.package.Environment') {
        env (id: 'windows') {
            homeDir ('C:\\Documents and Settings\\me')
            appName ('my.app')
        }
        env (id: 'linux') {
            homeDir ('/home/me')
            appName ('my.app')
        }
        env (id: 'macos') {
            homeDir ('/Users/me')
            appName ('my.app')
        }
    }
...
}
reporter You may specify a reporter class that will be used instead of the default LightestReporter to generate the report output. This class should both extend LightestTestListener and implement ILightestReporter . Currently only one reporter element is supported, though this may change.
config {
...
    reporter (class: 'my.package.Reporter')
...
}
dispatcherAssignmentStrategy You may specify a strategy class that will be used instead of the default SimpleDispatcherAssignmentStrategy to decide how task dispatchers (which are associated with test environments) get assigned to testcase classes. This class must implement IDispatcherAssignmentStrategy, and may for convenience extend QueuedDispatcherAssignmentStrategy to handle concurrency. There should be only one dispatcherAssignmentStrategy element.
config {
...
    dispatcherAssignmentStrategy (class: 'my.package.Strategy')
...
}

Core Classes Overview

SimpleApi

The SimpleApi class (com.googlecode.lightest.core.SimpleApi) provides a convenient way to define the set of tasks that are available to a given testcase. It can search one or more Java package paths for tasks by name, and returns the first task found. By default, all tasks in the current working directory of the test runner are included by SimpleApi instances.

Use addPackage(String packageName) to add a new package path to the API. For example, if your tasks are defined in the package com.sample.tasks, you could do:

def api = new SimpleApi()
api.addPackage('com.sample.tasks')

Or simply:

def api = new SimpleApi('com.sample.tasks')

SimpleApi implements IDomainSpecificApi, specifically its getTask(String name) method. You may use a custom implementation of this interface that doesn't obtain tasks by package at all, and uses some other mechanism.

LightestTestCase

All Lightest tests extend LightestTestCase (com.googlecode.lightest.core.LightestTestCase), which is responsible for properly interpreting tasks specified with the builder syntax in its test methods. Subclasses should call setApi(IDomainSpecificApi api) before invoking any tasks. This can be done in the constructor of the test class, or in a @Before method. In its simplest form:

class MyTest extends LightestTestCase {

    MyTest() {
        setApi(new SimpleApi())
    }
}

LightestTestCase itself subclasses GroovyTestCase so that the standard Groovy test assertions (extensions to the JUnit 3.8 assertions) are available. Note however that Lightest tests are not run by a JUnit runner; you must always use the @Test annotation to mark test methods and @Before / @After to mark fixture setup and teardown methods, respectively.

You can access the test environment (implementing ITestEnvironment) assigned to the testcase in any given test method, via the dispatcher:

    @Test
    void myTest() {
        def env = getDispatcher().getEnvironment()
        ...
        env.myLocalVar = 'foo'
        ...
    }

You can add local values to the environment in the scope of any test method, and these can be accessed by any tasks that are invoked, via the environment. Local values will be cleared from the environment after the method finishes. Just be sure you don't inadvertantly clobber a non-local value!

LightestTask

Each task used in a testcase should have as its implementation a corresponding subclass of LightestTask (com.googlecode.lightest.core.LightestTask). The task is responsible for performing some action, and populating a result object (see the next section) depending on whether the action succeeded or failed. Subclasses of LightestTask only have to implement a single method, doPerform(ITaskResult result):

class MyTask extends LightestTask {

    void doPerform(ITaskResult result) {
        println 'Been there, done that.'
        result.fail()
    }
}

Three key fields are available for inspection in task classes - config, prefs, and env .

The config object is essentially a groovy.util.Node from which the parameters to the task may be accessed. Attributes are accessed using the .'@attributeName' notation, and values can be accessed with .nodeValue() . For example:

MyTest.groovy
    @Test
    void myTest() {
        MyTask (attr1: 'foo', attr2: 'bar, 'baz')
    }
MyTask.groovy
    void doPerform(ITaskResult result) {
        println config.'@attr1'     // prints "foo"
        println config.'@attr2'     // prints "bar"
        println config.nodeValue()  // prints "baz"
    }

Two attributes on config have special meaning in the context of Lightest - description and breakpoint. If set, the String representation of description will be automatically visible with the task in the report. If for a given task breakpoint is set to any value that evaluates to true, the test will pause at that task if the runner is in interactive mode. You don't have to do anything in the task definition for these features to work.

Any preference values specified in the configuration file may be accessed from prefs. And any environment values may be accessed from env. Of course, local environment values may also be set on env..

ITaskResult

Executing a task always produces a ITaskResult (com.googlecode.lightest.core.ITaskResult). The values populated on this object will appear in the report for the test run. The important values to consider setting are status, message, responseData, and links . The ITaskResult object is passed into the doPerform() method, and should be populated therein.

The status of the result is what determines whether the task succeeded or failed. By default, the status is set to indicate success (STATUS_OK). Setting it to anything else indicates failure at some level. In order of increasing severity, you can invoke flag(), fail(), or doom() on the result object to do this.

Use setMessage(String message) to set an informational message to be displayed in the report. In particular, display any information related to why the task may have failed.

Use setResponseData(String data) to set larger chunks of text that may have been produced in performing the task.

Finally, use addLink(String link) to add a link to related resources, such as documents or screenshots. The link text will appear in the report, exactly as specified using this method. Multiple links may be specified.

Other Resources

- Haw-Bin Chai (hbchai @t gmail d0t com)