FitNesse Decision Tables
October 10, 2011 4 Comments
- FitNesse with .Net
- Installing FitNesse
- Adding FitNesse to your .Net Solution
- FitNesse Decision Tables
- FitNesse Query Tables
In the last post, we set up a solution to demonstrate the use of FitNesse. The solution contained a Calculator Project, and a Calculator.Specifications project which contains an instance of FitNesse, and an Acceptance Test fixture for the Calculator project.
To show that everything was up and running we created a simple Decision Table test in FitNesse.
In this post we’ll look more closely and Decision Tables.
Decisions Decisions
A FitNesse Decision Table allows us to supply a number of input parameters and receive back a number of output values. A test passes or fails based on whether the expected outputs match the actual outputs.
In our last post we tested a simple calculation using our Calculator project. Let’s look at the Markup for that Table, line by line.
Line 1 defines the name of the table, and by convention this also tells FitNesse the name of the Class it should try to use when executing the test. In this case FitNesse will search our TestFixtures for a class called DoSimpleMath. Alternatively the Fixture name ‘DoSimpleMatch’ could have been used in the table.
The Exclamation mark at the start of Line one is interesting. If the Table name had been written without spaces as described above, FitNesse would have automatically turned the table header into a link.
The Exclamation mark prevents links being automatically created. Strictly speaking in this instance it’s not needed, since FitNesse does not try to create links where spaces exist. It is however good practice to include the exclamation even when not needed.
Line 2 defines the parameters of the test, but the input values we’ll sent to the test, and the output values we get back. In this case A, B and Op are all input parameters. Result is an output value as indicated by the question mark ‘?’.
Line 3 consists of the values to be used with the Test. We supply 1, 2 and + and we state that we expect the value 3 to be the result of adding 1 and 2.
!|Do Simple Maths | |A |B |Op|Result?| |1.0|2.0|+ |3.0 |
Naturally, you can create multiple rows to test various scenarios.
!|Do Simple Maths | |A |B |Op|Result?| |1.0|2.0|+ |3.0 | |5.0|5.0|- |0 | |2.0|3.0|* |6.0 | |6.0|3.0|+ |2.0 |
Decision Table Fixtures
As mention above the name of the Table dictates the name of the class that FitNesse will attempt to execute the test.
It may be that a table name and the particular input and output columns are ideal for describing features of the system, but are not good names for objects in our domain model.
This is where Fixtures come in. Generally speaking we don’t want to write FitNesse tests that directly access the domain model. Apart from the fact that good names for tests may not make good interfaces for objects, there is also a brittleness from hooking up directly to a Domain Model that could change.
Test Fixtures provide a level of abstraction between FitNesse and our System Under Test. Fixtures are usually simple pass through objects that invoke the expected behaviour and return apropriate results.
We declare the inputs as public fields. There’s no benefit in declaring properties and private fields in a fixture. We want the simplest possible implementation that allows us to get values in and out.
public class DoSimpleMaths
{
public decimal A;
public decimal B;
public string Op;
public decimal Result()
{
if (Op == "+")
return Calculator.Add(A, B);
if (Op == "-")
return Calculator.Subtract(A, B);
if (Op == "*")
return Calculator.Multiply(A, B);
if (Op == "/")
return Calculator.Divide(A, B);
throw new NotImplementedException(string.Format("'{0}' is not an implemented Operator", Op));
}
}
The following fixture implements the Result output as a function. If your Decision Table includes multiple outputs you can implement each as a separate function for each.
public class DoDivisionWithRemainder
{
public int A;
public int B;
public int Result()
{
return A / B;
}
public int Remainder()
{
return A % B;
}
}
If the work of the fixture can be implemented in a single method, you could consider the following alternative approach. Use public fields for all inputs and outputs, then use a method called Execute to populate all of the outputs.
FitNesse will run the ‘Execute’ method before evaluating the outputs.
public class DoDivisionWithRemainder
{
public int A;
public int B;
public int Result;
public int Remainder;
public void Execute()
{
Result = A / B;
Remainder = A % B;
}
}
The following FitNesse Decision Table will work with either of the previous two Test Fixtures.
!|Do Division With Remainder| |A |B |Result? |Remainder? | |13 |5 |2 |3 |
Beyond the Basics
We can do some interesting things beyond the basic decision tables shown above. For example if we have inputs that will be the same for each row in the table, we can define it once in the header.
!|AddAFixedPercentage |10 | |Principal |Result?| |0 |0.0 | |10 |11.0 | |100 |110.0 |
In the above example, the value 10 is passed into the constructor of the fixture. It can then be used for each row, without needing a column for it in the table.
public class AddAFixedPercentage
{
public decimal principal;
private decimal _percentage;
public AddAFixedPercentage(decimal <span class="hiddenGrammarError" pre="">percentage)
{
_percentage</span> = percentage;
}
public decimal result()
{
return Calculator.AddPercentage(principal, _percentage);
}
}
If you want to pass more than one parameter to the Fixture you can do that. Just add them to the first row in the table. Make sure that the constructor has the correct number of parameters of the correct types to accept the values in the table.
!|FixtureName |10 |ABC |3.14 |
When testing our expected results against the actual results, we also have options. We don’t need to find an exact match in order to pass a test. Sometimes an approximate match, or a range of values may be sufficient. Let’s remind ourselves of the markup for an exact match.
!|Do Simple Maths | |A |B |Op|Result?| |6 |2 |/ |3 |
If we use the ~= operator we can match on approximately equal values.
|22|7|/ |~=3.14 |
22/7 is the famous approximation of PI, but in reality it’s not all that close an approximation. In fact it all goes wrong if you look beyond 2 decimal places. The Test above will pass because at two decimal places, 22/7 matches 3.14.
We can also check that a value is Grater Than another.
|10|1|+ |>10 |
Or that a value falls within a given range.
|5|3|* |14<_<16 |
When Decision Tables Work Best
As mentioned above, Decision Tables are very useful when we have a set of clearly defined Inputs and Outputs. It may seem that most problems can be reduced to this sort of scenario, and that’s probably true, however we’ll see other options in subsequent posts for other types of scenarios.









Pingback: Adding FitNesse to your .Net Solution | Devjoy
Pingback: FitNesse with .Net | Devjoy
Pingback: FitNesse with .Net – Query Tables | Devjoy
Pingback: FitNesse with .Net – Query Tables | Devjoy