< Testing With FIT
| Testing With FitNesse >
This is only the HTML version of the original WiKi-based tutorial.
You should download it from here to experience the real thing.
The main class is TimeRecording. The following methods are called by the test:
So far, so good...so what? Where is the connection between these methods and our FIT table? How does the FIT framework know when to call which method? How does it create the objects needed to call the methods? Let's have a look at the steps of a FIT test:
So FITRunners main job is converting the HTML to the internal representation (and vice versa) and delegating control to the appropriate Fixture.
In our case we will use a ColumnFixture. Let's have a look at our table again:
The cells with the header day, from and to will be assigned to member variables of the Fixture, meaning for each row FIT will assign the value specified in the cell to the corresponding member. If there are braces or a question mark behind the header this will be interpreted as a method, and the expected value specified in the cell will be compared to the value returned by the method. So our Fixture must provide members and methods corresponding the header names. The Fixture code is found in class
http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeRecordingColumnFixture.java
Here an excerpt of the class
As you can see, the Fixture just delegates the calls to the TimeRecording. But how is an entry for the TimeRecording created by the values of the member variables? In the class TimeRecording there is just a method for adding a TimeRecord
But who the heck calls it...and how? Here we make use of a special method of the ColumnFixture. After assigining all values to member variables and before the first method call, ColumnFixture calls the method execute(). The default implementation doesn't do anything, but in our extension we take care of adding the TimeRecord here:
Also the ColumnFixture has a method reset() which is called at the beginning of the row, before assigning values to the member variables. But we have no use for that in our example.
In this case we have to overwrite the method responsible for the type conversion:
< Testing With FIT | Testing With FitNesse >
[.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.
How does this work?
Alright, it looks very nice. At first it was white, then it turned green. But what happened when we started the test? In short: FIT tested our time recording system against the specified expectations. Now the details: Let's start with the code that implements our time recording system.The Code under test
Our system is made up by the following classes:- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/Time.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeFrame.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeRecord.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeRecording.java
- http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeRecordingRepository.java
The main class is TimeRecording. The following methods are called by the test:
| public void addRecord(TimeRecord timeRecord) | Adds a new TimeRecord to the system |
| public double getRecordedTimeForDay(int day) | Returns the recorded time for the given day |
| public double getBreakForDay(int day) | Returns the break for the given day |
| public double getMandatoryBreak(double time) | Returns the mandatory break with respect to the given time |
| public double getWorkingTimeForDay(int day) | Returns the calculated working time by the system for the given day |
| public double getWorkingTimeUpToDay(int day) | Returns the calculated working time accumulated to the given day |
So far, so good...so what? Where is the connection between these methods and our FIT table? How does the FIT framework know when to call which method? How does it create the objects needed to call the methods? Let's have a look at the steps of a FIT test:
Cycle of a FIT test
So what happens in detail if we run a FIT test?- At first, the FITRunner reads the HTML document and creates an internal representation.
- FITRunner looks for the next table
- The Fixture specified in the table header is instantiated
- FITRunner hands the representation of the table to the Fixture and delegates control to it.
- The Fixture calls the code under test with the data specified in the table and checks the results against the expectations specified in the table
- The Fixture modifies the table, e.g. by turning the expectations green or red.
- The Fixture returns control to the FITRunner
- FITRunner creates a result document from the internal representation.
So FITRunners main job is converting the HTML to the internal representation (and vice versa) and delegating control to the appropriate Fixture.
The Fixture
The Fixture is the glue-code between FIT and the classes under test. The FIT Framework expects a subclass of fit.Fixture, which provides a set of methods for processing the internal table representation and a bunch of utility methods. But the Fixture class itself doesn't do anything, you have to write a subclass which performs the appropriate interaction with the system under test. FIT already provides three subclasses which ease this task in most cases:In our case we will use a ColumnFixture. Let's have a look at our table again:
| de.fitsample.timerecording.TimeRecordingColumnFixture | |||
| day | from | to | working time? |
| 1 | 6:00 | 8:00 | 2.0 |
| 2 | 6:00 | 9:00 | 3.0 |
| ... | |||
The cells with the header day, from and to will be assigned to member variables of the Fixture, meaning for each row FIT will assign the value specified in the cell to the corresponding member. If there are braces or a question mark behind the header this will be interpreted as a method, and the expected value specified in the cell will be compared to the value returned by the method. So our Fixture must provide members and methods corresponding the header names. The Fixture code is found in class
http://files/FitTutorial/FitSample/src/de/fitsample/timerecording/TimeRecordingColumnFixture.java
Here an excerpt of the class
public class TimeRecordingColumnFixture extends ColumnFixture {
public int day;
public Time from;
public Time to;
private TimeRecording timeRecording;
public TimeRecordingColumnFixture() {
timeRecording = new TimeRecording();
TimeRecordingRepository.getInstance().store(timeRecording);
}
public double recordedTime() {
return timeRecording.getRecordedTimeForDay(day);
}
public double recordedBreak() {
return timeRecording.getBreakForDay(day);
}
public double mandatoryBreak() {
return timeRecording.getMandatoryBreak(timeRecording.getRecordedTimeForDay(day));
}
public double workingTime() {
return timeRecording.getWorkingTimeForDay(day);
}
public double sum() {
return timeRecording.getWorkingTimeUpToDay(day);
}
...
As you can see, the Fixture just delegates the calls to the TimeRecording. But how is an entry for the TimeRecording created by the values of the member variables? In the class TimeRecording there is just a method for adding a TimeRecord
public void addRecord(TimeRecord timeRecord)
But who the heck calls it...and how? Here we make use of a special method of the ColumnFixture. After assigining all values to member variables and before the first method call, ColumnFixture calls the method execute(). The default implementation doesn't do anything, but in our extension we take care of adding the TimeRecord here:
public void execute() {
timeRecording.addRecord(new TimeRecord(Tag, new TimeFrame(from, to)));
}
Also the ColumnFixture has a method reset() which is called at the beginning of the row, before assigning values to the member variables. But we have no use for that in our example.
Typeconversion
So FIT assignes the cell values to the corresponding member vairables day, from and to. In the table these values are specifies as Strings, but how are they converted to the types of the members? Well, for primitive types like int, float, String, etc. FIT already provides implicit conversion. But how about other types like our Time class?In this case we have to overwrite the method responsible for the type conversion:
public Object parse(String text, Class type) throws Exception {
if (type == Time.class) {
return Time.valueOf(text);
}
return super.parse(text, type);
}
< Testing With FIT | Testing With FitNesse >
[.FrontPage] [.RecentChanges]