How to specify hierarchical data? #GivenWhenThenWithStyle

Given-When-Then examples work nicely with structured data, particularly if it can fit well into tables. Things become tricky with data that has more than two levels of hierarchy. For example, a scenario might involve several users, each with several addresses and accounts, and transactions within each account. This does not fit neatly into a single table. The challenge for this week is describing those kinds of hierarchies in Gherkin.

Below are a few common options for you to choose, based on what I’ve seen in the wild. This challenge is probably more open-ended than the previous ones, since there are many other ways to solve the same problem. If you know of a better way, please post your solution somewhere and send us the link (using the voting form linked at the end of this post).

Option 1: chain together individual entities

The first way of specifying hierarchical data is to start at a higher level for the context (in this case “user”), and use it to provide context for the following statements, implicitly specifying the hierarchy:

Given user Leto
With the following addresses
| type   | street address  | city     |
| home   | Central Plaza 1 | Caladan  |
| office | Grand Palace    | Arrakeen |
And the following account
| type    | currency | balance | status |
| current | USD      | 100     | active |
And the following transactions in account
| date      | amount | description   |
| 2 January |  2000  | flight ticket |
| 3 January |  1500  |   desert suit |
And the following account
| type    | currency | balance | status |
| credit  | USD      | -400    | active |
And the following transactions in the account
| date      | amount | description |
| 1 January |  5000  | spice       |
| 2 January |  7500  | spice       |
| 4 January |  5500  | spice       |

Given user Vladimir
With the following addresses
| type   | street address     | city    |
| office | Shield Wall Street | Carthag |
...

Option 2: relational table normalisation

Alternatively, instead of chaining entities to provide context, we could introduce identifiers and just represent the hierarchy as flat tables, similar to a relational database.

Given the following users:
| userid  | name     | 
|   UID_1 | Leto     |
|   UID_2 | Vladimir |
And the following addresses:
| userid | type   | street address     | city         |
| UID-1  | home   | Central Plaza 1    | Caladan      |
| UID-1  | office | Grand Palace       | Arrakeen     |
| UID-2  | office | Shield Wall Street | Carthag      |
| UID-2  | home   | Star Jewel 2       | Giedi Prime  |
And the following accounts:
| accountid | userid |  type   | currency | balance | status |
| AID_1     | UID-1  | current | USD      | 100     | active |
| AID_2     | UID-1  | credit  | USD      | -400    | active |
| AID_3     | UID-2  | credit  | RUB      | -400000 | active |
And the following transactions:
| accountid | date      | amount | description   |
| AID_1     | 2 January |  2000  | flight ticket |
| AID_1     | 3 January |  1500  | desert suit   |
| AID_2     | 1 January |  5000  | spice         |
| AID_2     | 2 January |  7500  | spice         |
| AID_2     | 4 January |  5500  | spice         |
...

Option 3: embed hierarchy as text

Gherkin does not have a good way to embed tables into tables, but it does support free-form text enclosed in three quotes. We could use a hierarchical text format (such as YAML, JSON, or even just simple indentation) and then parse the string into a hierarchy of objects in the step implementation. This would allow us to specify the entire user hierarchy in a visual way, at the expense of more complex parsing.

Given the user
"""
name: Leto
addresses:
  - type: home
    street: Central Plaza 1
    city: Caladan
  - type: office
    street: Grand Palance
    city: Arakeen
accounts:
  - type: current
    currency: USD
    balance: 100
    status: active
    transactions:
      - date: 2 January
        amount: 2000
        description: flight ticket
      - date: 3 January
        amount: 1500
        description: desert suit
  - type: credit
    currency: USD
    balance: -100
    status: active
    transactions:
      - date: 2 January
        amount: 75000
        description: spice
      - date: 3 January
        amount: 5500
        description: spice
"""
And the user 
"""
name: Vladimir
addresses:
  - type: home
    street: Star Jewel 2
    city: Giedy Prime
"""
...

Option 4: use data in external files

Instead of embedding all that hierarchical data, we could also move it to an external file, and provide just the file name to the automation step:

Given the user Leto with data from users/leto_a.txt
And the user Vladimir with data from users/vladimir_h.txt

Participate in the challenge

Choose one of the options you like the best, or propose your own solution. You can post short answers directly in the form below. For longer explanations, perhaps post your suggestion somewhere and send us the link.

To participate, send your answers by Monday 22nd February. We will post the results on Tuesday 23rd February.

Stay up to date with all the tips and tricks and follow SpecFlow on Twitter or LinkedIn.

PS: … and don’t forget to share the challenge with your friends and team members by clicking on one of the social icons below 👇