Expressing tests in a Given When Then style is the core practice of the Behavior Driven Development (BDD) methodology. Details about BDD can be found here.
Writing tests in a GWT style can become tricky when there is no clear understanding / definition of what the actual test and preconditions are.
The Four Phase Test steps:
The setup step puts the system in a specific, well known state.
The exercise step stimulates the system and brings it into a new state. The stimulation is the actual feature under test.
The verification step is nothing else than the comparison between the expected and actual state of the system.
Finally the tear-down step allows the test process to clean after itself.
From a functional (business) point of view the tear-down step does not have any value and this might be the reason why it has been dropped in the GWT style.
GWT is nothing else than the Four Phase without the tear-down step.
The previous definition of the GWT style testing seems to rely on the concept of state of the system. Not all the features in a system rely on the state of the system itself. A natural question then is: is the Given step always necessary when writing GWT tests? The short answer is, of course, NO.
Before proceeding, let’s step back and try to classify tests with a pinch of scientific approach!
Time dependant or stateful tests
All the tests where the history of the system is somehow relevant to determine how the system will react to a user stimulation, fall under this category.
A simple example is, for instance, accessing user details in a web-app protected by authentication.
An authentication failure or the nonexistence of the user will prevent the test from being executed. A successful user authentication is a necessary precondition required for the correct execution of the test.
A GWT test would look like:
- Given the user is successfully authenticated on the system
- When the user clicks on the details button
- Then the name is displayed
- And the last name is displayed
- And the date of birth is displayed
Another example is the attempt of redeeming an expired deal:
- Given I bought a deal
- And the deal is expired
- When I try to redeem the voucher
- Then an error is displayed
A graphic representation of this kind of tests could be:
A – represents the initial status
f – is the user action (the feature under test)
B – represents the final status
If the actual status B matches the expected status then the test completed successfully.
From a math point of view if we think of the user action as a mathematical function, a stateful test satisfies the condition:
B = f(A)
If the resulting status is C instead of the expected B then we found a bug!
Time independent or stateless tests
No matter when it’s tested, but 2+2 it’s always going to be 4. Assuming we have for example a service that performs a mathematical calculation, no matter when the feature is tested, but its results will always (hopefully!) be the same.
Under these circumstances the Given step loses its importance and can be omitted
The only interaction with the system (the actual test) would be enough to perform assertions.
Assuming we’re testing a summation service a typical WT would look like:
- When I sum 5 and 7
- Then the result is 12
Mathematical oriented features are not the only ones belonging to this category. A few more examples are:
- Currency or time conversion
- Picture Resize
- Echo service
Now that some context has been given, let’s proceed with a more accurate definition of the GWT style
A given statement is required when the feature under test requires either
- the system to be in a specific state (eg. user authentication)
- an action to happen before the feature under test can be invoked (eg. ticket bought, the browser has loaded a page)
- time related constraints are met (eg. expiration date)
Sometimes the given step is mistakenly used as initialization or setup step. Some examples could be:
- Prepare data that will be consumed during the When step
- initialize resources (db connection, remote services)
- pre-load data on database
Renaming/rewriting of a Given into a business action
From a business perspective a “Given the database is prepopulated…” is not of any use. At the same time though, these data are fundamental to the correct execution of the test. A good way of resolving this issue is to replace the “Given the database is pre-populated …” with the business action that led to the creation of these data, such as “Given a user is registered on the system”.
Initializing resources like db / rest connections should not be listed in the GWT steps. Most of the current BDD frameworks provide developers with test setup phase where required resources can be initialized.
A when statement represents the feature under test. While in a GWT test there can be multiple given or then, there should be one and only one when.
Then(s) are the verification or assertion steps. It is a good habit to have then(s) steps to assert one single condition per then, and there should not be more than two or three then(s) in a GWT test.
Having too many then(s) is a symptom of testing too much or testing two features at the same time.
In my enterprise we recently introduced Test-Driven Development (TDD) as a programming technique for delivering robust and reliable software.
The lifecycle of tasks is the following:
The “To Do” and “In Progress” phases are self-explanatory. When a task goes in “For Review” the developer choose, with a round-robin approach, one of the team mates, and together they review the code in order to ensure quality (eg. check the code is clear, correct design and design patterns, high code coverage). Last but not the least it comes the “Verified” phase, during which the developer ensure that new features behave as expected in System Test.
There have been serveral attempts to make the “For Review” phase appealing, interesting and efficient. After some meeting and discussions we came up with the following check-list.
- Overall Design
- Development Prctices
- Error Handling
Even if we, in my humble opinion, perfectly described what should happen in a review phase, when we put it in practice, results were not so exciting as we were expecting.
What you really want to achieve in a code(peer)-review, is to ensure that the code is clear, well designed and correctly tested (in a TDD fashion!). What we were doing was to make the developer lead the review process and tell what the code was doing. Under these circumstances a reviewer would make zero or nearly no effort in understanding what the code was actually doing. Finally the “code coverage check” simply turned into a “check sonar code coverage %”. This could guarantee in really few circumstances that the quality and clarity criteria were met.
Since the TDD approach expects tests to be written before the actual code, why reviews should not be structured in the same way?
Few days after I finished to read the “Clean Code” book, I decided to play a game with a colleague for testing how well I learnt principles uncle bob explained in his book.
I asked him to guess, just reading from a bunch of test classes, what my code would have done. The result was surprising. With only a few variables and methods renaming, my colleague was able to correctly guess what my code was trying to do.
The review process honestly started very slowly because I, the developer, was giving as less hints as possible and was letting my colleague to progress alone as much as he could. Once sorted the initial naming incongruences, the review itself turned into a vivid and exciting conversation.
We agreed that
- the code was clear because he could guess with a little effort and nearly no suggestions what the code was trying to do.
- the code was well designed because class hierachies and patterns I used were thoughtful
- I correctly followed the TDD approach because I guaranteed a very high code coverage
What I learnt that day is that in order to understand whether or not you wrote clean and well tested code is to simulate somebody to work on your code in a day you’re off. If he/she’s able to do that without ringing you.. well.. you did a good job!
Thoughts on the review process
- Reviews have to be interesting. If the review process turns into something boring, it will not give results you expect. This can be achieved challenging your reviewer!
- In a review process the reviewer is the one who has to talk the most, if it is the developer, well, you have a smell there!