Benad's Web Site

If you don't already know, there is roughly three types of testing you can do to attest the quality of your software: unit testing (testing a single module or class), functional testing (or integration testing; validating the overall functionality of the whole software against the specifications) and performance testing (speed, memory, scalability...).

Now if you want to test a GUI in Java implemented with Swing, how do you do it? Well, for performance, you'll have to improvise by asking "potential users" to use the GUI for a couple of hours, and see if they think the GUI is "easy to use" or "responsive", etc.

But for functional testing, you should have a clear set of requirements in the specs, for example "if you click button 'Add', then the sum of fields 'A' and 'B' should be placed in field 'Sum'. Even more complex, you have scenarios like "if you press enter in either field 'A' or 'B', then it is as if you clicked on button 'Sum'". So you have a GUI that looks like this:

The code for when you click on "Add" and when you press enter are pretty simple:

private void bFieldActionPerformed(java.awt.event.ActionEvent evt) {                                       
  addButton.doClick();
}
private void aFieldActionPerformed(java.awt.event.ActionEvent evt) {                                       
  addButton.doClick();
}
private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {                                          
  double aVal, bVal;
  try {
    aVal = Double.parseDouble(aField.getText());
  } catch (NumberFormatException ex) {
    sumResultLabel.setText("Field A is not a number");
    return;
  }
  try {
    bVal = Double.parseDouble(bField.getText());
  } catch (NumberFormatException ex) {
    sumResultLabel.setText("Field B is not a number");
    return;
  }
  sumResultLabel.setText(Double.toString(aVal + bVal));
}

That was pretty simple, but when you want to do functional testing, are you going to manually use the GUI for every test? Well, not if you're using UISpec4J. Automated testing, done with JUnit, would be done like this for the above two specifications:

public void testCorrectSum() {
  Panel panel = new Panel(new MyWindow());
  panel.getInputTextBox("aField").insertText("2.5", 0);
  panel.getInputTextBox("bField").insertText("3.5", 0);
  panel.getButton("Add").click();
  assertEquals(6.0, Double.parseDouble(panel.getTextBox("sumResult").getText()), 0.0);
}
public void testEnterKey() {
  Panel panel = new Panel(new MyWindow());
  panel.getInputTextBox("aField").insertText("2.5", 0);
  panel.getInputTextBox("bField").setText("3.5"); //this does the "press enter"
  assertEquals(6.0, Double.parseDouble(panel.getTextBox("sumResult").getText()), 0.0);
}

Wow, that was simple. Combine this with FitNesse, a wiki-based functional testing environment (see this for a quick example), and you now have a great way to automate all functional testing and changes in the specifications (and the GUI).

Before you jump on those libraries, here are some caveats you have to be aware of:

  • UISpec4J is at version 0.13 at the time I'm writing this. The API could change between releases (hence the "alpha" status), and not all Swing components are supported. It worked fine for me though.
  • UISpec4J finds you components based on the "name" attribute, which is set with the setName function. By default the name is empty when you add new components with NetBeans, so be careful.
  • Swing usually needs a GUI environment to run, so even though UISpec4J hides everything from the screen, if you try running this on Linux with no X Server running, Swing will simply refuse to run and the tests will fail. The solution for this if you plan to run this on a server is to run X within a VNC server even if you don't plan to connect to it (vncserver man page from TightVNC).
  • You still can't test the visual aspect of the GUI, i.e. the way it looks like, without a manual test.

Published on October 9, 2005 at 15:58 EDT

Older post: Java Coding Style Tools

Newer post: When ego destroys open source