Wednesday, 2 May 2012

A breakdown of the Given, When, Then steps

In this post I try to explain what I think the various step blocks in the GWT structure are for.

Given

The “Given” part of a scenario is probably the hardest thing to implement and get right. The reason for this difficulty is that you have to balance the need for reducing complexity of the scenario by ensuring that only relevant context is stated whilst implementing the functionality to allow the context to be defined in this way. The “Given” step forms the configuration or setup phase, you are defining what context the scenario is running in and as such you need to manage datasets, add data, remove data, modify data, create users etc whatever is necessary to get the system into the correct state ready for the scenario to executed.

As an example, imagine a scenario where a member of a gym walks into a club, they have been sick for a long period so they “froze” their membership (this means paying a smaller amount for the duration of their sickness but keeping the membership open), and they ask the receptionist to unfreeze their membership.

The story:

Feature: Unfreeze membership
In order to resume a membership after returning from a long term sickness period
As a receptionist
I want to unfreeze a membership

The following two scenarios show two different ways of representing the same scenario, the first uses multiple Given steps to set the context where the second looks to simplify this into:

Example Scenario 1:

Scenario: Unfreeze regular monthly payer
Given a member joined on 01/01/2010 onto plan ‘Monthly’
And the member freezes their account on 01/02/2011 for 12 periods
And the current business day is 15/04/2011
When I unfreeze their membership
Then the member should be charged £10 freeze fee
And their status should be ‘OK’
And their payment status should be ‘Arrears’

Example Scenario 2:

Scenario: Unfreeze regular monthly payer
Given a frozen member
When I unfreeze their membership
Then the member should be charged £10 freeze fee
And their status should be ‘OK’
And their payment status should be ‘Arrears’

You can see that we have taken what was three separate steps has been combined into a simple “Given a frozen member” statement. The first thing you will probably ask is but what about the information such as join date and the freeze date and duration pieces of information, well what we really want to do here is have this information “inferred” so whenever members of the team refer to “a frozen member” they know that it refers to a member that joined on 01/01/2010 onto a monthly plan etc and we would set that information up as defaults which can be overridden if required. So you could do something like:

Given a frozen member with the following properties
| Key | Value |
| JoinDate | 15/01/2010 |

This gives us the ability to take all of the defaults of a frozen member and yet override them with values that are relevant and mean something within the current scenario. Keeping your Given statements concise and to the point plays valuable role in ensuring your tests remain readable and maintainable over the long term.

My personal preference is to make all “Given” steps non-UI based actions, this is because using the UI is the slowest and most brittle way to get things done and the point of the “Given” is to get your tests setup as quickly as possible.

When

The “When” phase is the event under test. This should be the main action that is being defined by the specification and I normally find this step to be the easiest to define and implement as it is the step that makes the call to the api or executes the UI automation code. There should be an obvious tie between the scenario title and the actions performed in the “When” steps otherwise you will have a mismatch between what you expected the specification to do and what it actually does.

Then

Finally, the “Then” phase is where you perform any assertions of correctness and you can run numerous checks and validations to ensure that the action that was performed during the “When” phase actually completed successfully and that all of the relevant data sets, files, databases etc have be been updated according to the expected behaviour.

When executing “Then” steps I try to use routes through the system such as alternative apis or use an external mechanism such as an Entity Framework, LINQ to SQL to validate databases or the .NET System.IO classes to validate the file system etc.

1 comment:

Daniel Meineck said...

I think this post could really help me in my current role ;)