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
libsubdirectory should further have
pythonchild directories. The
javadirectory is where the jemmy and jython jars will reside,
lib/pythonis where the python standard library will live.
- Download Jemmy and Jython. If Jython hasn't reached 2.2 final yet, 2.2a1 is very stable.
Install Jython, and then copy jython.jar to
lib/javaand the contents of the Lib directory from within the installation directory to
Copy jemmy.jar into
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.