...
Definition |
---|
The RuleForInterpreter is used to express concrete and measurable business rules.
|
Specific keywords for expected values
offers a list of useful keywords to support the Business Expert.
Empty cells | When a test cell is left blank, | only shows the returned value
---|---|
error | When you expect an error, specify it in the cell to test that particular behavior |
Coloring
will visually show the test result by coloring each testing cell:
...
The return value of the quotient method is also a double, which means that the values provided in the quotient? expected column must be doubles as well. When
compares the value returned by the fixture with the value provided as an expectation, it will first convert the expected value to the type of the actual returned value. In the fifth row, it will convert the value 6 to a double and then do the comparison.A More Realistic Example
The Calculator example is very simple. In a real world example, the fixture code would not perform any real work but would instead delegate to the application under development. In other words, if this was a real application the fixture would not carry out the division operation but call on the system under development. The general rule is to keep the fixture as thin as possible to be merely a mediator between the example table and the application code.
...
- given values, which are mapped to public instance variables in the fixture class
- expected values, which are checked against values returned by the corresponding public instance methods
Headers
For a given column header cell,
:...
- It figures out the public instance method to use using camel casing rules.
- If there is no such method or if it's not publicly accessible, it marks the cell with an error annotation, causing the cell to appear yellow and to display a stack trace of the error. That column will be ignored entirely.
Columns
will then run all remaining rows one at a time, going through all cells in the row from left to right.
...
DEFINITION |
---|
The collection interpreters are used to express any kind of groups, lists or sets of values. When a collection interpreter is executed, compares the list of values expected with the list of values returned by the system under development. The test result depends on the specific collection interpreter selected.
|
Specific keywords
none
Coloring
will visually indicate the test result by coloring the rows:
...
Writing fixtures for List of Value
As we've seen in the Collection Interpreters definition, the collection interpreters are used to express a collection of data to be compared with the system under development.
When running the table, uses a fixture to mediate between the example expressed in collection of values tables and the system under development. The fixture code defines how the specific lists of values are mapped to the application code.
This page shows the fixture code that supports the examples introduced in the
Workflow validation (Do With)
Definition
...
definition.
Using the CollectionInterpreter alone
Consider the example of collection of values table described in definition, shown again below.
list of | Canada Province Codes |
Name | Code |
ALBERTA | AB |
BRITISH COLUMBIA | BO |
NEW BRUNSWICK | NB |
MANITOBA | MB |
NEWFOUNDLAND and LABRADOR | NL |
NOVA SCOTIA | NS |
NUNAVUT | NU |
ONTARIO | ON |
PRINCE EDWARD ISLAND | PE |
QUEBEC | QC |
SASKATCHEWAN | SK |
YUKON | YT |
OTHER PROVINCE | OP |
The first cell of the first row indicates that a the ListOfInterpreter will be used to interpret the example table. The next cell says that the query() method to use is in the fixture named Canada Province Codes. In Java, the name of the fixture is the name of a Java class. The returned value of the query() method must be a Collection which is, in our example, a Set of Provinces.
The second row, also known as the header row, designates the attribute columns of the Collection's elements. In our example, Name and Code are the attribute of the Province.
The fixture code to support this example in Java is the class CanadaProvinceCodesFixture shown below.
The query method
The GreenPepper method called to get the list of data from the fixture is query() in Java and Query() in C#.
Code Block | ||
---|---|---|
| ||
public Collection query() {...} |
The return type of the query method does not have to be specifically a Collection.
It can be any of the derived Collection class or an Array.
Code Block | ||
---|---|---|
| ||
public Employees[] query() {...} |
You can choose another method then query by telling GreenPepper which method to use with the help of an annotation or attributes.
Code Block | ||
---|---|---|
| ||
import com.greenpepper.reflect.CollectionProvider;
...
@CollectionProvider
public Collection query() {...} |
but the method specifies still have to be parameter-less and return a Collection implementation or an array.
Show me the code
Code Block | ||||
---|---|---|---|---|
| ||||
public class CanadaProvinceCodesFixture
{
public Set<Province> query()
{
return Country.canada().provinces();
}
} |
Code Block | ||||
---|---|---|---|---|
| ||||
public class Country
{
private String name;
private Set<Province> provinces = new TreeSet<Province>();
private Country(String name)
{
this.name = name;
}
public static Country canada()
{
Country canada = new Country("CANADA");
canada.provinces.add(new Province("ALBERTA","AB"));
canada.provinces.add(new Province("BRITISH COLUMBIA","BC"));
canada.provinces.add(new Province("MANITOBA","MB"));
canada.provinces.add(new Province("NEW BRUNSWICK","NB"));
canada.provinces.add(new Province("NEWFOUNDLAND and LABRADOR","NL"));
canada.provinces.add(new Province("NOVA SCOTIA","NS"));
canada.provinces.add(new Province("NUNAVUT","NU"));
canada.provinces.add(new Province("ONTARIO","ON"));
canada.provinces.add(new Province("PRINCE EDWARD ISLAND","PE"));
canada.provinces.add(new Province("QUEBEC","QC"));
canada.provinces.add(new Province("SASKATCHEWAN","SK"));
canada.provinces.add(new Province("YUKON ","YT"));
return canada;
}
public Set<Province> provinces()
{
return provinces;
}
}
public class Province implements Comparable
{
public String name;
public String code;
public Province(String name, String code)
{
this.name = name;
this.code = code;
}
public int compareTo(Object o)
{
return name.compareTo(((Province)o).name);
}
} |
How is the table processed?
When it runs this table, reads the first row to select the interpreter and fixture. It then reads the second to know what are the attribute columns. Finally it starts testing from the third row down to the end of the table.
For the third row carries out the following sequence of steps:
- It calls the method query() of the fixture CanadaProvinceCodesFixture to retrieve the Collection to test.
- It reads the value ALBERTA from the column Name and compares it to the attribute Name of the first element of the List.
Since the values are equal, it will annotate the cell as right, which results in the cell being colored green. - It reads the value AB from the column Code and compares it to the attribute Code of the first element of the List.
Since the values are equal, it will annotate the cell as right, which results in the cell being colored green.
Step 2 and 3 are repeated through the remaining rows of the table.
For the fourth row, the Codes are not the same so will mark the expected cell wrong. The cell will be colored red and will display a message including the expected value and the actual value.
The order of Provinces NEW BRUNSWICK and MANITOBA are inverted compared to the alphabetical sorting. will annotate both rows as wrong. Each cell will be colored red and will display a message including the expected value and the actual value.
The last row is not part the set of Province returned by the system under development. In that particular case, will insert the keyword missing and color the row in red.
Using a CollectionInterpreter joined with the DoWithInterpreter
In this particular case, there is only one fixture combining the methods of the CollectionInterpreter and the methods of the DoWithInterpreter. So, in the CollectionInterpreter table, the second cell of the first row says which method to call from the DoWithInterpreter fixture.
Consider the example of the Phone Book application as described in Collection Interpreters definition. The DoWithInterpreter will insert entries in the Phone Book. The ListOfInterpreter is then used to test that the Phone Book really contains the inserted entries.
1. We use the DoWithInterpreter to create our personal phone book.
do with | phone book | ||||
insert | Fred | Flintstone | with number | (123) 456-7890 | |
insert | Barney | Rubble | with number | (123) 321-7666 | |
insert | Great | Gazoo | with number | (123) 989-4455 |
2. The test to be performed is: The requirement list should be the same as the SUD list.
list of | Phone book entries |
FirstName | LastName |
Fred | Flintstone |
Betty | Rubble |
Great | Gazoo |
Wilma | Flintstone |
Show me the code
Code Block | ||||
---|---|---|---|---|
| ||||
public class PhoneBookFixture
{
private PhoneBook phoneBook = new PhoneBook();
public void insertWithNumber(String firstName, String lastName, String number)
{
phoneBook.insert(new PhoneBookEntry(firstName, lastName, number));
}
public List<PhoneBookEntry> query()
{
return phoneBook.entries();
}
} |
Code Block | ||||
---|---|---|---|---|
| ||||
public class PhoneBook
{
private List<PhoneBookEntry> entries = new ArrayList<PhoneBookEntry>();
public void insert(PhoneBookEntry entry)
{
entries.add(entry);
}
public List<PhoneBookEntry> entries()
{
return entries;
}
}
public class PhoneBookEntry
{
public String firstName;
public String lastName;
public String number;
public PhoneBookEntry(String firstName, String lastName, String number)
{
this.firstName = firstName;
this.lastName = lastName;
this.number = number;
}
} |
Writing fixtures for derived List of Value (SetOf, SubsetOf, SupersetOf)
The fixture writing and results annotations are exactly similar in all points.
Of course the behavior of the test will vary see Collection Interpreters definition for detail.
Workflow validation (Do With)
Definition
DEFINITION |
---|
The DoWithInterpreter is used to express interactions with the system under development that must be performed in a particular order. This form of specification provides information about the business flow. When a sequence of action is executed, confirms that each action has successfully been performed.
|
Specific Keywords
offers a list of useful keywords to support the Business Expert. Those keywords are placed at the beginning of an action row.
Accept | Confirm that the action as been executed by the system under development. |
---|---|
Check | Verify the specified expected value with the value returned by the system under development |
Reject | The action should not be performed by the system under development (expected errors). |
Display | Print the value returned by the system under development. |
Coloring
will visually show the test result by coloring each testing cell:
Panel | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
When the action has been executed successfully, color the cell(s) in green. |
Panel | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
If the action execution has failed, color the cell(s) in red. |
Panel | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
If the system encounters an execution error, the cell is colored yellow and provides information about the error. |
Panel | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
When the action has been executed successfully, will display the returned value in gray. |
Standard form (without keyword) | Only the Action description will be colored. |
---|---|
Accept | Only the cell containing the keyword Accept will be colored. |
Check | The cell containing the expected value will be colored. In case of a failure, will show the expected and the returned values. |
Reject | Only the cell containing the keyword Reject will be colored. |
Display | A new cell at the end of the row will be colored containing the returned value. |
Writing fixtures for Do With tables
As we've seen in the Do With definition, a sequence of tables is used to express a business flow in the application under development.
When running the table, uses a fixture to mediate between the example expressed in the sequence of tables and the system under development. The fixture code defines how the specific actions are mapped to the application code.
This page shows the fixture code that supports the examples introduced in the Writing a Do With specification(link to-do).
Fixture for Bank
Consider the first example of business flow described in Writing a Do With specification(link to-do), shown again below.
do with | bank |
open checking account | 12345-67890 | under the name of | Spongebob | Squarepants |
check | that balance of account | 12345-67890 | is | $0.00 |
end |
The first table indicates to use a DoWithInterpreter, which handles a business flow expressed as a sequence of tables. The fixture Bank will do the mediation with the application under development.
The interpreter will run all the tables until the end of the document. In this case, the second and third tables compose the business flow example.
The second table indicates to perform the action open checking account under the name of on the system under development, with the parameters 12345-67890, Spongebob and Squarepants. That action will result in a call to the method openCheckingAccountUnderTheNameOf() on the fixture with the parameters 12345-67890, Spongebob and Squarepants.
The third table indicates to check the result of the action that balance of account is on the system under development with the expected value $0.00. That action results in a call to the method thatBalanceOfAccountIs on the fixture with the parameter 12345-67890. That method is expected to return a value, which will be asserted for equality against the domain representation for the value $0.00.
The fixture code to support this example in Java is the class BankFixture shown below.
Show me the code
Code Block | ||||
---|---|---|---|---|
| ||||
public class BankFixture
{
private Bank bank;
public BankFixture()
{
bank = new Bank();
}
public boolean openCheckingAccountUnderTheNameOf(String number, String firstName, String lastName)
{
return bank.openCheckingAccount(number, new Owner(firstName, lastName)) != null;
}
public Money thatBalanceOfAccountIs(String accountNumber) throws Exception
{
BankAccount account = bank.getAccount(accountNumber);
return account.getBalance();
}
} |
That class follows the general rules of fixtures described in Fixture Conventions. It provides public instance methods openCheckingAccount and thatBalanceOfAccount to map respectively to the actions open checking account and that balance of account.
Workflow validation (Scenario)
...