Abbot and Costello Primer

Abbot is essentially a two-part framework: the first part, Abbot, allows us to test our Swing apps using standard Java; the second part, Costello, allows us to record our tests manually and then replay them in JUnit. Now let's look at how to record a test using Costello. At the moment, Costello has no documentation (another great reason to buy this tutorial!). The primary use of Costello is to record a series of actions performed on some Swing app, and then to play them back. To record a script with Abbot you need to make sure that your test app is in Costello's classpath. Once you've done that you can either type

java -jar abbot.jar // launches costello

or call

abbot.editor.Costello.main(new String[]);

If you're running Costello from within Eclipse, you'll probably want to just make a new Run configuration that calls the latter. Everything in your project's classpath will be in Costello's, which makes life that much easier. Once you've launched Costello, choose File > New Script… and save it somewhere in your project. Select the first line in the list "Insert your launch information here" and an editor frame will appear on the right.

Java Click To expand

So, what do we see here?

Now you're ready to actually record something. Just to make sure everything you need is ready, click Run and make sure the widgets you want to test load up correctly. Your app will most likely launch and then close immediately. Once you know that Costello has everything in its classpath and was able to find the method you were hoping it would, you can choose Capture > All Actions (no motion) or Capture > All Actions. The former is generally what you want as it will capture all the significant events but won't bother to record the actual MouseEvent.MOUSE_MOVED events. And no, if you play back a recording that saved mouse events, your pointer won't start zooming around your screen all by itself! Now select Start Recording, click on the important items, type where you need to, Drag, etc.. One thing to be aware of here is that dragging requires Robot mode. If you see a "Robot non-functional, falling back to AWT mode" message while starting Costello, then any dragging events won't work. Clicking and typing will continue to function as normal, though. Also be aware of how Costello treats key modifiers: when trying to record Alt+f Costello only recorded the f without the Alt modifier. Hopefully the developers will fix this soon. Once you have finished recording you can close your app and switch back to Costello to finish the recording sequence. When you want to run the test again, just click Run; Costello will load up your app, perform all your operations, and terminate it. What happens when things don't go as they should? An easy way to test this is to just change the arguments to one of your actions. When Abbot gets to that point in the script, the line will turn red and processing will stop. Considering that this is a functional test and not a unit test, it makes sense to stop processing since one function is generally dependant upon the previous one. You might expect that it would just cancel operation on the current sequence, but instead it cancels all upcoming events and leaves your app open.

Java Click To expand

A couple other oddities: While there is a Cut option in the Edit menu, there's no Paste, so it is really more of a misnamed Delete. Also, Costello can have a tendency to spit out copious errors to STDOUT. Just ignore them. That's normal. Now, onto using Abbot to replay our test in a JUnit TestCase. First we start with the Abbot ScriptFixture (junit.extensions.abbot.ScriptFixture) which extends the JUnit TestCase class to allow us to interact with our app and the Costello tests we write. To integrate our test (which is now stored as an XML file), we simply extend the ScriptFixture class and load the XML files in the suite() method.

public class ExampleTest extends ScriptFixture {
 public static Test suite() {
 return new ScriptTestSuite(ExampleTest.class, “src/example/scripts/ExampleTest”);

Then, in our main method we call

TestHelper.runTests(args, ExampleTest.class);

What does all of this do? Basically the ScriptTestSuite function accepts a class (this test) and a pointer to the XML file in the classpath, and then it runs that test. Pretty simple, huh? Now let’s take a peek at the XML file that gets generated by Costello to get a feel for things:

 <component class="javax.swing.JLayeredPane" id="JLayeredPane Instance" index="1" parent="JRootPane Instance" window="SwingSet" />
 <component class="javax.swing.JPanel" id="JPanel Instance" index="0" parent="JLayeredPane Instance" window="SwingSet" />
 <component class="javax.swing.JRootPane" id="JRootPane Instance" index="0" parent="SwingSet" />
 <component class="javax.swing.JTabbedPane" id="JTabbedPane Instance" index="1" parent="Main SwingSet Panel" window="SwingSet" />
 <component class="demo.SwingSet" id="Main SwingSet Panel" index="0" name="Main SwingSet Panel" parent="JPanel Instance" window="SwingSet" />
<component class="javax.swing.JFrame" root="true" title="SwingSet" />

First, Abbot defines the components that we are interacting with; this includes the Frames and Panels that are visible during our test.

<launch args="[]" class="demo.SwingSet" classpath="." desc="Insert your launch information here" method="main" threaded="true" />

Next, it defines our launch arguments for the Swing class that we are testing. Nothing too fancy here.

 <action args="JTabbedPane Instance,&quot;SplitPane&quot;" class="javax.swing.JTabbedPane" method="actionSelectTab" />
 <action args="JTabbedPane Instance,&quot;TableView&quot;" class="javax.swing.JTabbedPane" method="actionSelectTab" />
<terminate />

Now, the fun bits—interaction with our app. As you can see here we have two actions, both of which were selectTab. First we selected the SplitPane tab and then the “TableView” tab, both of which were recorded by Costello for playback. Now let’s run through some more real-world type tests to see what happens.