< 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.
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:
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:
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:
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.
|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.
< New Requirements | Gui Test with other Fixtures >
[.FrontPage] [.RecentChanges]
This is only the HTML version of the original WiKi-based tutorial.
You should download it from here to experience the real thing.
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:
- With enter you enter values into fields.
- The action press means clicking a button.
- With check you check values of fields.
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
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/ui/TimeRecordingTable.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/ui/TimeRecordingTableModel.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/ui/TimeRecordingUI.java
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:
- In the first row the ActionFixture is created which then takes control.
- The action start creates our real Fixture.
- Now if the ActionFixture finds an enter, it will search for a method with a name that comes after enter and calls it with the value in the next cell as a parameter.
- On press a method with the name found in the next cell is called.
- On check a method with the name found in the next cell is called. The value returned be the method is compared to the expected value specified in the next cell.
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]