Platinum Partner
java

Festive Functional Tests for Swing GUIs

Very recently, Alex Ruiz announced the 1.0 Alpha release of FEST-Swing. An opportune moment to explore what it gives you. As opposed to unit tests, which focus on particular methods in an application, functional tests evaluate user scenarios. For example, instead of testing whether method "getUsers" works, a functional test walks through a small yet comprehensive scenario that a user of the application would be expected to complete. For example, in the case of an anagram game, a functional test would enter some text into a text field, click a button, and then compare the returned message with the message that the test writer would expect to be returned. Something like this, in semi-pseudo code:

window.textBox("anagramField").enterText("abstraction");
window.button("guessButton").click();
window.label("resultLabel").requireText("Correct! Try a new word!");

The cool thing is that the above isn't pseudo code at all. It is FEST-Swing (Fixtures for Easy Software Testing). Here is the whole test class in its entirety:

import com.toy.anagrams.ui.Anagrams;
import org.junit.Test;
import org.fest.swing.fixture.FrameFixture;
import org.junit.After;
import org.junit.Before;

public class AnagramFestTest {

private FrameFixture window;

@Before
public void setUp() {
window = new FrameFixture(new Anagrams());
window.show();

}

@Test
public void shouldEnterAnagramAndReturnTrue() {
window.textBox("anagramField").enterText("abstraction");
window.button("guessButton").click();
window.label("resultLabel").requireText("Correct! Try a new word!");
}

@After
public void tearDown() {
window.cleanUp();
}

}

That's not bad for a test. When you run the above, the anagram application starts up and then you can see with your own two eyes some text being entered in the text field, the button being clicked, and the result being returned, after which a success/failure output is given, with some helpful info for debugging. And, as you can see, you can use it together with JUnit (or TestNG, if that's what you prefer). The arguments to the "textBox", "button", and "label" invocations are the names of the Swing components in question. So, in the case of the JTextField below, one can see that the name property is set to "anagramField" below, which is sufficient for the FEST infrastructure to find it in the test above:

Especially when you compare it to, for example, the NetBeans XTest framework, the succinctness of FEST is even clearer. With the XTest framework, the meat of the above test would be something like this:

public void shouldEnterAnagramAndReturnTrue() {
JFrameOperator frmAnagrams = new JFrameOperator("Anagrams");
JLabelOperator lblGuess = new JLabelOperator(frmAnagrams, "Your Guess:");
JTextFieldOperator txtGuess = new JTextFieldOperator((JTextField)lblGuess.getLabelFor());
txtGuess.typeText("abstraction");
new JButtonOperator(frmAnagrams, "Guess").push();
JLabelOperator lblFeedback = new JLabelOperator(frmAnagrams, 2);
String expectedMessage = "Correct! Try a new word!";
assertEquals("Evaluation was wrong:", expectedMessage, lblFeedback.getText());
}

That code is quite a bit denser and more verbose. FEST benefits from its "fluent" approach, which points (as stated in fluent's co-originator Martin Fowler's blog) to its attempt "to be readable and to flow". You can literally knock a quick FEST test together without too much thinking, so long as you know the scenario you want to deal with and the names of the Swing components that are involved. Not much documentation is needed either if you play with your IDE's autocomplete functionality.

What's also pretty cool is that FEST's Alex Ruiz will be presenting at JavaOne this year, as this blog entry of his explains, together with an interesting outline of what one can expect.

Here are some resources, for if you're new to FEST and want to take it for a spin:

Finally, there's more to FEST than Swing GUI testing. Have a look at this article on FEST-Reflection, for example.
{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}