/ CDI, FEST, TESTNG

TestNG, FEST et CDI

No, those are not ingredients for a new fruit salad recipe. These are just the components I used in one of my pet project: it’ss a Swing application in which I wanted to try out CDI. I ended up with Weld SE, which is the CDI RI from JBoss.

The application was tested alright with TestNG (regular users know about my preference of TestNG over JUnit) save the Swing GUI. A little browsing on the Net convinced me the FEST Swing testing framework was the right solution:

  • It offers a DSL for end-to-end functional testing from GUI.
  • It has an utility class that checks that Swing components methods are called on the Event Dispatch Thread (EDT).
  • It may check calls to System.exit().
  • It has a bunch of verify methods such as requireEnabled(), requireVisible(), requireValue() and many others that depend on the component’s type.

The challenge was to make TestNG, FEST and CDI work together. Luckily, FEST already integrates TestNG in the form of the FestSwingTestngTestCase class. This utility class checks for point 2 above (EDT use rule) and create a "robot" that can simulates events on the GUI.

Fixture

FEST manages GUI interaction through fixtures, wrapper around components that can pilot tests. So, just declare your fixture as a test class attribute that will be set in the setup sequence.

Launch Weld in tests

FEST offers an initialization hook in the form of the onSetup() method, called by FestSwingTestngTestCase. In order to launch Weld at test setup, use the following implementation:

protected void onSetUp() {
	// container is of type WeldContainer
	// it should be declared as a class attribute in order to be cleanly shutdow in the tear down step
	container = new Weld().initialize();

	MainFrame frame = GuiActionRunner.execute(new GuiQuery<MainFrame>() {
		@Override
		protected MainFrame executeInEDT() throws Throwable {
			return container.instance().select(MainFrame.class).get();
		}
	});

	// window is a test class attribute
	window = new FrameFixture(robot(), frame);
	window.show();
}

This will display the window fixture that will wrap the application’s main window.

Generate screenshots on failure

For GUI testing, test failure messages are not enough. Fortunately, FEST let us generate screenshots when a test fails. Just annotate the test class:

@GUITest
@Listeners(org.fest.swing.testng.listener.ScreenshotOnFailureListener.class)
public abstract class MainFrameTestCase extends FestSwingTestngTestCase {
	...
}

Best practices

Clicking a button on the frame fixture is just a matter of calling the click() method on the fixture, passing the button label as a parameter. During developement, however, I realized it would be better to create a method for each button so that it’s easier for developers to read tests.

Expanding this best practice can lead to functional-like testing:

selectCivility(Civility.MISTER);
enterFirstName("Nicolas");
enterLastName("Frankel");

Conclusion

I was very wary at first of testing the CDI-wired GUI. I thought it would be hard and would be too time-consuming given the expected benefits, I was wrong. Uniting TestNG and CDI is a breeze thanks to FEST. Having written a bunch of tests, I uncovered some nasty bugs. Life is good!

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
TestNG, FEST et CDI
Share this