List Validation (List of, Set of, Superset of, Subset of)
Definition
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:
As expected, the row is returned by the system under development.
A row is missing or in surplus in the list returned by the system under development.
If the system encounters an execution error, the cell is in yellow, and provides information about the error.
Particular behavior for the list of interpreters:
Since the ListOfInterpreter expects to match exactly the expected list and the list returned by the SUD, compares each cell of the table separately. If the expected value is different from the returned value, colors the cell in red and provides the two values.
Particular behavior for the superset of interpreters:
Since the SupersetOfInterpreter accepts that the specification may contain rows that are not contained in the SUD, will not color the rows contained in the specification but not returned by the SUD.
Writing fixtures for List tables
Writing fixtures for List of Value
As we've seen in the Collection Interpreters, 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 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 method called to get the list of data from the fixture is query() in Java.
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.
public Employees[] query() {...}
You can choose another method then query by telling LivingDoc which method to use with the help of an annotation or attributes.
import info.novatec.testit.livingdoc.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
public class CanadaProvinceCodesFixture { public Set<Province> query() { return Country.canada().provinces(); } }
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
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(); } }
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.