Assert object pattern

One of the most significant problems with tests written by developers is the fact that such tests do not verify business invariants but the underlying technical details.

When a developer writes a shopping cart part of the application and implements adding an item to the reservation, the test most likely looks like this:

val reservation = Reservation(...)
val item = Item(...)

reservation.add(item)

reservation.items has size 1
reservation.items.head shouldEqual item
reservation.totalPrice shouldEqual item.price * 1.23

The developer wants to know whether the shopping cart contains the added item, there are no other items in the shopping cart, and whether the VAT tax has been added to the total price of the reservation.

What is wrong with that? This code dissects the objects. I look at the code, and all I see are technical details. Where is the meaning?

Step 1. Hide the assertion

How can we write such tests better? We can use the Assert Object pattern. It is an object that wraps the result and exposes methods which verify the object’s properties. The most trivial usage of this pattern would look like this:

val reservation = Reservation(...)
val item = Item(...)

reservation.add(item)

val assertion = Assert(reservation)
assertion.hasSize(1)
assertion.hasItem(item)
assertion.hasPrice(item.price * 1.23)

It hides the dissecting of the result, but it does not look much better than the previous example.

Step 2. Show the meaning

Fortunately, we can fix that. If we invest some time in implementing the assert objects, we can create a nice fluent interface:

val reservation = Reservation(...)
val item = Item(...)

reservation.add(item)

Assert(reservation)
 .hasItem(item)
 .hasNoOtherItems()
 .hasItemPriceWithVATTax(item)

Why is it better? This is the text we had in the Jira ticket. The text that was written in the specification is written in code. The test shows the user’s intent.

Why don’t we do it?
We must create such assert objects ourselves. We must write the methods of the fluent interface. Assert objects are not given to us for free. It is much easier to import assertions from a testing library and verify the technical details.

Older post

5 best books I read in 2018

A list that surprised even me…

Newer post

A Python HTTP server for serving static content

How to easily serve static content on localhost or in the local network