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.

  • As for all other interpreters, the first row of the collection interpreters specifies the name of the interpreter and the name of the collection to be tested.
  • The next row is used to define the name of each attribute related to the members of the collection of data.
  • The following rows are used to specify the set of values to test.

Specific keywords

none

Coloring

 will visually indicate the test result by coloring the rows:

Green

As expected, the row is returned by the system under development.

Red

A row is missing or in surplus in the list returned by the system under development.

YELLOW

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 ofCanada Province Codes
NameCode
ALBERTAAB
BRITISH COLUMBIABO
NEW BRUNSWICKNB
MANITOBAMB
NEWFOUNDLAND and LABRADORNL
NOVA SCOTIANS
NUNAVUTNU
ONTARIOON
PRINCE EDWARD ISLANDPE
QUEBECQC
SASKATCHEWANSK
YUKONYT
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

 

Code for the CanadaProvinceCodesFixture
public class CanadaProvinceCodesFixture
{
    public Set<Province> query()
    {
        return Country.canada().provinces();
    }
}
Code of the System Under Development
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:

  1. It calls the method query() of the fixture CanadaProvinceCodesFixture to retrieve the Collection to test.
  2. 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.
  3. 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 withphone book
insertFred Flintstonewith number(123) 456-7890
insertBarney Rubblewith number(123) 321-7666
insertGreat Gazoowith number(123) 989-4455

2. The test to be performed is: The requirement list should be the same as the SUD list.

list ofPhone book entries
FirstNameLastName
FredFlintstone
BettyRubble
GreatGazoo
WilmaFlintstone

Show me the code

 

Code for the PhoneBookFixture
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 of the System Under Development
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.