Tuesday, 14 October 2008

Label verbose items to simplify back-references

This is quite an obvious little pattern, but I think it's still worth documenting.

Some repetition is harmless
When I'm writing an example of a required behaviour, I find that I often have to refer to something I've already mentioned. For example:

Given the following names: Charles, Naomi, Melissa, Arnold
Searching for 'ar' should find: Charles, Arnold

Here, I have mentioned the names Charles and Arnold twice: once when describing the context and once when describing the expected outcome. This isn't a problem because I purposely kept the names short to make the example easy to follow.

But repetition can become awkward
If the values are long or complicated then the examples can become hard to read and maintain. For example:

Given the following addresses:
18 Cedar Row, Enfield, Middx, EN8 9TT
"The Grange", 177 Hounslow Road, Epping, Essex, HA10 4PL
2b Armsfield Avenue, London, SE1 2BN
80 Commercial Street, Aberdeen, AR19 1TB
Searching for 'ar' should find:
18 Cedar Row, Enfield, Middx, EN8 9TT
2b Armsfield Avenue, London, SE1 2BN
80 Commercial Street, Aberdeen, AR19 1TB

So, use labels for verbose values
Labelling each item allows you to use the label, instead of the value, whenever you need to refer to it.

Given the following addresses:
(1) 18 Cedar Row, Enfield, Middx, EN8 9TT
(2) "The Grange", 177 Hounslow Road, Epping, Essex, HA10 4PL
(3) 2b Armsfield Avenue, London, SE1 2BN
(4) 80 Commercial Street, Aberdeen, AR19 1TB
Searching for 'ar' should match addresses: (1), (3), and (4)

I call them labels or pseudo-identifiers to distinguish them from real identifiers in the system under test. For example, in the implementation we might have a database table called Address with an identifier column called addressId. But the identifiers we use in the examples are merely a way of making the example easier to read. They are not a reflection of any particular database model. Any mapping between real identifiers and pseudo-identifiers must always be handled behind the scenes in the fixture code.

The labels don't have to be numeric. They could be letters (A, B, C) or other more meaningful short strings.

Labels can also help you to hide details
Another advantage of labels is that they can let you gloss over unnecessary details. For example:

Example acceptance test showing use of pseudo-identifiers

Using labels for bookings (1, 2) and for booking references (A, B) means we don't need to go into any details of what we're booking or what the booking references look like. If the format of the booking references is important, we can cover that in another test, but, in this test, we're not locking ourselves into any particular format. All we're doing is demonstrating the rule: "Each booking is given a unique booking reference that can be used to look-up the booking."

The fixture code will have the following methods:


public class IdentifyingBookingsTest extends ConcordionTestCase {

public void makeBooking(String bookingNumber, String bookingRefAlias) {
...
}

public String lookupBooking(String bookingRefAlias) {
...
}
}

Having this extra level of indirection may make the fixture code work harder, but that is not a problem. It is much better to put complexity and implementation-related assumptions in the fixture code, where we have powerful refactoring tools at our disposal, than to complicate the specification and make it more fragile.

1 comment:

Duncan Pierce said...

Nice idea! Have you considered using HTML label elements? (http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1). Perhaps less useful is the acronym element, which is for defining abbreviations (http://www.w3.org/TR/html401/struct/text.html#h-9.2.1).