AcceptanceTestsWithFitNesse.
GuiTest
< New Requirements | Gui Test with other Fixtures >

This is only the HTML version of the original WiKi-based tutorial.

You should download it from here to experience the real thing.

 Settings

UI-based TimeRecording Test

I can hear the FIT envangelists yelling Don't you never ever perform FIT tests based on the UI. Test the business logic for christ's sake. Well, nail me to the cross if you like. Testing the business logic is one thing, but this doesn't help if the graphical user interface is not working correctly. So if you are a first class hardliner, skip to Testing Datasets. You're still reading? So let's go on. FIT provides a special Fixture for testing UI interactions: The ActionFixture.

The ActionFixture is based on the following metaphor:

Meaning with this Fixture you can simulate the user interactions. In order to fool around with this Fixture we created a tiny little GUI for our time recording system.



Now we would like to test our system using the ActionFixture by clicking the Test button:

de.fitsample.ActionFixture
slowMotion 200
start de.fitsample.timerecording.ui.TimeRecordingUIFixture
enter day 1
enter from 6:30
enter to 12:00
press add
enter from 13:30
enter to 16:15
press add
check working time 8.25
check sum 8.25
enter day 2
enter from 6:30
enter to 16:15
press add
check working time 9
check sum 17.25
enter day 3
enter from 10:00
enter to 12:00
press add
check working time 2
check sum 19.25
enter from 12:45
enter to 17:00
press add
check working time 6.25
check sum 23.5
enter day 4
enter from 8:00
enter to 12:00
press add
check working time 4
check sum 27.5
enter from 13:00
enter to 18:30
press add
check working time 9.5
check sum 33

Tried it? Cooool..., but how does this work? Let's have a look at the relevant UI code first. You will find this code in the classes

For us the focus is on the class TimeRecordingUI. Here an excerpt with UI components of interest:
public class TimeRecordingUI extends JFrame {

protected JButton addButton;
protected JTextField dayTextField;
protected JTextField fromTextField;
protected JTextField toTextField;
protected JTable timeRecordTable;
...

So the table describes the workflow and the expected results. But the real interaction with the UI components happens in our Fixture. One thing that's remarkable is that we are dealing with two Fixtures: The ActionFixture, and the Fixture that actually performs the interaction with the UI components. How does this work? Let's have a closer look to the cycle of an ActionFixture test:

That means in a table row like
|enter|from|9:00|
a method from() is called with the value 9:00 as parameter.
|press|add|
calls the method add()
|check|working time|9.5|
calls the method workingTime() and checks if the returned value is 9.5. If so, the cell is turned green, otherwise red.

This means our Fixture has to provide the appropriate methods. Let's see:
public class TimeRecordingUIFixture extends Fixture {

private TimeRecordingUI timeRecordingUI;

public TimeRecordingUIFixture() {
timeRecordingUI = new TimeRecordingUI();
timeRecordingUI.pack();
timeRecordingUI.setVisible(true);
}

public void day(String day) {
timeRecordingUI.dayTextField.setText(day);
}

public void from(String from) {
timeRecordingUI.fromTextField.setText(from);
}

public void to(String to) {
timeRecordingUI.toTextField.setText(to);
}

public void add() {
timeRecordingUI.addButton.doClick();
}

public double workingTime() {
TableModel model = timeRecordingUI.timeRecordTable.getModel();
Object value = model.getValueAt(model.getRowCount() - 1,
TimeRecordingTableModel.WORKING_TIME_COLUMN);
return ((Double) value).doubleValue();
}

public double sum() {
TableModel model = timeRecordingUI.timeRecordTable.getModel();
Object value = model.getValueAt(model.getRowCount() - 1,
TimeRecordingTableModel.SUM_COLUMN);
return ((Double) value).doubleValue();
}
}

The methods from(), to() and add() do not need any further explanation. workingTime() and sum() are not that hard either, they just retrieve the needed value from the TableModel.


Slow Motion

In the second row there is something we did not explain yet:
|slowMotion|200|

Well, if we would run the original fit.ActionFixture you could hardly follow the UI interactions, since they are much too fast. That's why we made our own extension de.fitsample.ActionFixture, which provides the additional (optional) command slowMotion. If slow motion is used the Fixture will take a nap after each command. The value after slowMotion is the duration of the nap in milliseconds, which is in our case a nap of 200ms.
public class ActionFixture extends fit.ActionFixture {

private long slowMotionMs;

public void slowMotion() {
slowMotionMs = Long.parseLong(cells.more.text());
}

public void enter() throws Exception {
super.enter();
sleep();
}

public void check() throws Exception {
super.check();
sleep();
}

public void press() throws Exception {
super.press();
sleep();
}

public void start() throws Exception {
super.start();
sleep();
}

protected void sleep() {
if (slowMotionMs < 1) {
return;
}
try {
Thread.sleep(slowMotionMs);
} catch (InterruptedException excep) {

excep.printStackTrace();
}
}
}


< New Requirements | Gui Test with other Fixtures >


[.FrontPage] [.RecentChanges]