Tuesday, 17 April 2007

Swing Testing with Jython and Jemmy Part 1 - Setting up the system

Introduction

Testing is an important part of the software development process, and various types of testing need to be combined in order to make sure a product is sufficiently tested. A full set of unit tests goes a long way toward making a stable product, and brings with it a safety net to catch errors made when refactoring the code base. Unit tests a far from the whole story however; they are by nature highly localised, and so can't test the overall behaviour of a system. Functional tests go a step further in this regard than unit tests, wiring together various different components and checking that they work together correctly. At a higher level still are system tests, which should test the system as a whole, and that you can use the software to achieve what it is designed to do. Orthogonal to system tests, but at the same sort of level are acceptance tests, tests designed to see whether the product is suitable for the customers to use. Acceptance tests need to check the more superficial (but nevertheless important) aspects of the product. Does the product meet usability targets? Can the user cause crash the system by doing things wrong?

This post is intended to address the latter two types of testing: automating system and acceptance tests on the Java GUI. The basics of the technique requires two open source libraries: Jemmy, a GUI automation tool from the Netbeans team, and Jython, an implementation of Python written in Java.

Setting up the System

  1. Create a system-test folder, with tests and lib subdirectories. The lib subdirectory should further have java and python child directories. The java directory is where the jemmy and jython jars will reside, lib/python is where the python standard library will live.
  2. Download Jemmy and Jython. If Jython hasn't reached 2.2 final yet, 2.2a1 is very stable.
  3. Install Jython, and then copy jython.jar to lib/java and the contents of the Lib directory from within the installation directory to lib/python.
  4. Copy jemmy.jar into lib/java

You will now need to create a script to run your tests. Typically there will already be a script that is used to run the application that you want to test, and a copy of this script can be adapted to the job. In the case that the application is run by running the jar directly, you will need to examine the manifest in order to extract the classpath and main class for the script. The script will look something like the following:

#!/bin/bash
# file: run.sh
APP_DIR=/my/app
TEST_DIR=$APP_DIR/system-test

APP_LIB=$APP_DIR/lib
JAVA_LIB=$TEST_DIR/lib/java
PYTHON_LIB=$TEST_DIR/lib/python

CLASSPATH=$CLASSPATH\;$APP_LIB/anImportantLib.jar
CLASSPATH=$CLASSPATH\;$APP_LIB/anotherLib.jar

CLASSPATH=$CLASSPATH\;$JAVA_LIB/jemmy.jar
CLASSPATH=$CLASSPATH\;$JAVA_LIB/jython.jar

PYTHON_PATH=-Dpython.path="$PYTHON_LIB;./scripts;$TEST_DIR/tests;"

$JAVA_HOME/bin/java -cp $CLASSPATH $PYTHON_PATH org.python.util.jython $@

Note that this script will do nothing unless provided with a script name as an argument, and any arguments the script requires. As we will see later, the application itself is started within the test script. On windows, this can be converted to a batch script, or else run using Cygwin.

Writing the first script

The first script will simply start the application. Nothing more. It will go in the system-test/tests directory. Note that we start the app in a separate thread so that the running app doesn't block our tests from running!

# file: test.py
from co.uk.mycompany.myapp import MainApp
import sys

def run():
    MainApp.main(sys.argv[1:])

def main():
    startup = Thread(target=run)
    startup.start()

if __name__ == "__main__":
    main()

So, after that bit of work, we are back where we started, except that now we have to do something like the following to start the app:

./run.sh tests/test.py more args here

The next article will go into more detail about using jython and jemmy to do some actual work.

No comments: