Testing Java Swing components with Fest

entrada antigua del 28/3/2011 – old post from 3/28/2011

—–

While exploring into new ways of writing automated unit test cases in Java, I discovered the Fest framework.

Besides some nice tools for mocking and wrapping calls to reflection, Fest has a convenient API to automate unit tests for Swing components leveraging the AWT Robot, which is too low-level as to be of real use for massive unit testing.

Of course, this is valid for integrated/assembly tests, not real unit tests, because Fest launches a Swing frame or dialog and then reproduces user gestures in the application (go to that field, enter that text, select that on the combo, press this button and so on). I find it useful because, especially in Swing, a thorough unit test suite is not enough to ensure proper user experience and bug-free deliveries. You need to test integrated, all the Swing widgets, event handlers and even business logic.

Results have been very good. Fest has some bugs but even with that I was able to write a good quantity of unit tests in a decent time. I will show some examples in this post.

NOTE: Actually the test were written for code that is not accessing Swing directly but using an extended component model that we have built on top of Swing. +1 to Fest for being able to handle them without any extra worries.

First of all, I added a dependency to Fest in my pom.xml (or equivalent in your IDE):

<dependency>
    <groupId>org.easytesting</groupId>
    <artifactId>fest-swing</artifactId>
    <version>1.2</version>
    <type>jar</type>
    <scope>test</scope>
</dependency>

Then, I created my assembly test case as a POJO – we are using JUnit 4:

package project.test;

public class AssemblyTestCase { 
}

It is recommended to turn on an automated check to verify that all Swing components updates are done in Swing’s EDT (Event Dispatcher Thread). For those unfamiliar with the EDT, it is responsible for handling and updating all Swing widgets in a separate thread, causing that the application never loses responsiveness to user gestures (just in short, more about the EDT here). To do that, we add the following hook to the test:

import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
import org.junit.BeforeClass;
...
    @BeforeClass
    public static void setUpOnce() {
        FailOnThreadViolationRepaintManager.install();
    }

By doing that, Fest will check that the EDT is properly used. Very convenient!

Next step is to launch the frame or dialog. As JUnit runs in its own thread, we must launch the frame or dialog through Fest, to ensure, again, that EDT is properly used:

import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
import org.fest.swing.fixture.FrameFixture;
import org.junit.Before;
... 
    private FrameFixture testFrame; 
    private AllTypesFrame  frame;
... 
    @Before 
    public void setUp()  { 
        frame =  GuiActionRunner.execute(new GuiQuery<AllTypesFrame>() { 
            protected AllTypesFrame executeInEDT() { 
                return new AllTypesFrame(); 
            }
        }); 
        testFrame = new FrameFixture(frame); 
        testFrame.show(); 
    }

And also, unload the frame and associated resources:

import org.junit.After;
... 
    @After 
    public void tearDown ()  { 
        testFrame.cleanUp(); 
    }

Now that we are ready, let’s for for some actual tests. In this example, we assert that initially the button named JButton3 is initially disabled, then we will enter some text in the field named SensibleTextField1, some text in field SensibleTextField3 that is not valid, then delete the last character and assert that it is now valid.

import org.junit.Test;
... 
    @Test 
    public void test() {
        testFrame.button("JButton3").requireDisabled(); 
        testFrame.textBox("SensibleTextField1").enterText("test string"); 

        // SensibleTextField3 only allows integers up to  1,000,000 
        testFrame.textBox("TextField3").enterText("10000000");
        assertFalse(frame.getAllTypesObject1().getSlong().isValid()); 

        testFrame.textBox("TextField3").
            pressAndReleaseKey(KeyEvent.VK_BACK_SPACE);
        assertTrue(frame.getAllTypesObject1().getSlong().isValid()); 
    }

Once done, just run the test as always. I have verified that you can run them from Eclipse as with any other JUnit test, run them using the eCobertura Eclipse plug-in (nice way of using Cobertura tool in the IDE), run them with Maven, Hudson and even with Sonar!

Just a couple of important things to have in mind:

  • When you run the tests in your local computer, ensure that you are not doing anything else meanwhile. You can interfere with some keyboard and mouse events and produce faulty tests.
  • When you run the tests with Hudson, if it is installed as a Windows service, don’t forget to allow the service to interact with the desktop. Otherwise the Java VM will not have enough privileges to create Swing components (headless vs. headed display).

That’s all for now about Fest. I will continue playing with the tool and check what else it has to offer and keep you posted.

Happy Fest!

Author: deors

senior technology architect in accenture, with a passion for technology related stuff, celtic music and the best sci-fi, among other thousand things!

1 thought on “Testing Java Swing components with Fest”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s