May 8, 2012 6 Comments
Now that Cacio is finally released and promoted to Maven central repositories, I want to provide you a quick HOWTO about testing user interfaces.
For writing GUI tests, I am using FEST. However, one problem with running GUI tests is that they need to create windows, grab keyboard focus, and do all sorts of interaction with the screen. This has several disadvantages:
- When running on a developer machine, it requires to not touch anything while running the test suite, otherwise tests may fail or get blocked, e.g. because keyboard focus cannot be acquired or a test window suddenly goes into the background when it should not, etc. This can be quite annoying, especially with large test suites.
- When running on a Unix-based continuous integration server, it’s possible to utilize xvfb driver to create a virtual framebuffer, but I still often noticed problems that seem to come from asynchronous behaviour of the X architecture. For example, a test would draw a border in RED, and when checking some pixels to be red, they are not. They would only turn red after some unknown time, when the drawing commands have been processed by the X server and graphics card.
- When running on Windows based CI server, this sort of asynchronous problems don’t occur, but to make up for it, Windows has its own share of problems. First of all, on Windows you need a real screen/graphics card to be present (bad on servers). Even worse, on many Windows servers, you need a user to be logged in, and stay logged in, and the CI server running in that session to be able to access the screen. On other servers, multiple concurrent logons are possible, but not sharing a screen, e.g. when some guy logs into the CI server to do some admin work, it would grab the screen from the CI user, etc. All very complicated and time consuming to setup.
This is where Cacio-tta comes into play. It provides a graphics stack for the Java VM, that is completely independent from the environment. It renders everything into a virtual screen, which is simply a BufferedImage, and is driven solely by java.awt.Robot events. This makes it a perfect fit for GUI testing environments. And using it is very easy. There are two ways do it, and I usually combine them.
1. Include Cacio in your Maven dependencies
Simply add the following in your pom.xml:
<dependency> <groupId>net.java.openjdk.cacio</groupId> <artifactId>cacio-tta</artifactId> <scope>test</scope> </dependency>
2. Run your test with CacioTestRunner
Add the following annotation to your test class:
If you are using FEST and want to take advantage of its additional capabilities (create screenshots on failure, run tests in EDT, etc), use:
instead. Those annotations will make your test run in a Cacio-tta virtual screen environment
3. Optionally, run the whole test suite in Cacio
In some cases, it may be necessary to run the whole test suite in Cacio-tta. In order to do so, add the following to your pom:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12</version> <configuration> <systemPropertyVariables> <java.awt.headless>false</java.awt.headless> <awt.toolkit>net.java.openjdk.cacio.ctc.CTCToolkit</awt.toolkit> <java.awt.graphicsenv>net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment</java.awt.graphicsenv> </systemPropertyVariables> </configuration> </plugin>
This makes sure that Cacio is loaded instead of the default toolkit. This may be necessary, if any of your tests load any AWT, Java2d or Swing class, and are not annotated with the above annotation. This is because Java only allows to set the toolkit once, and it cannot be unloaded or unset. When you load any GUI class before loading the CacioTestRunner, the default toolkit will be loaded, and tests will not run in Cacio.
4. For non-Maven based builds
Of course, Cacio can also be used in non-Maven builds (ant, make, ..). Just download the Cacio sources (http://ladybug-studio.com/downloads/cacio/) build them, include the JARs in your project somehow, and add the annotations as described above, or set the system properties
java.awt.headless as described in the Maven snippet above.
Last but not least, if you encounter any problems with Cacio or the above instructions, let us know!