Clear and Readable Language
The purpose of Cucumber is to provide a clear and readable language for people (the humans) who need to understand a test’s function. Cucumber is designed to simplify and clarify testing.
For me, Cucumber is an efficient and pragmatic language to use in testing, because my entire development team, including managers and business analysts, can read and understand the tests.
Gherkin is the domain-specific language of Cucumber. Gherkin is significant because as a language, it is comprehensible to the nontechnical humans that need to make meaning out of tests.
In simpler terms: Gherkin is business readable.
Why add variables to Gherkin & Cucumber?
An unfortunate side effect of Cucumber is that in order to keep things readable, especially when dealing in multiples, it is all too easy to explode the number of behind the scenes steps. To avoid the confusion caused by an exorbitant number of steps, the simplest fix is to create user variables in the Gherkin. Variables are not natively supported by Gherkin, but that does not mean they cannot be used or added. Adding variables that allow you to reduce steps and maintain readability.
In the years since the development of Cucumber, many tips and tricks have proven useful. The usage of variables is by far the most valuable of these tricks. Variables are ways to communicate data from one step to the next, to pass a reference that other steps can act upon. This is most useful when dealing with data that has hierarchical aspects. This can range from machines that have parts, customers that have orders to make, and blogs that have posts to be posted. The idea is that sooner or later you have multiples of something, let’s call them widgets, in a single test, and you need a way to communicate which widget you are referring to in your step. A simple way to solve this is to give them names, and hence variables were born.
Efficient use of variables in Gherkin keeps your Cucumber in it’s intended state: clear and readable.
Let us consider a human resources application for this example. Say we want to create different data setups to simulate the retirement of a person in the hierarchy. When a person retires we want to make sure that any reports of this person are moved to report to their manager. First, we need to define the organization:
Given a tiny organization
Given a Team Lead with 3 employees
Or, we could use some history:
Given a Team Lead And add 3 employees
All three of the above issues have their perks and can handle the scenario simply enough. However, if we want to add a second level, an additional employee, the scenario quickly becomes more complicated. Let’s look at the 3 options with another layer of complexity.
Given a small organization
Chances are that people have to dig into the code to figure out the precise meaning. And once you have to look at the code behind the Gherkin, the efficiency value of using Cucumber is lost, as the goal is to communicate clearly and concisely.
Given a Director with a Team Lead with 3 Employees
This would be a new step, not an ideal scenario; let’s look at option 2:
Given a director And add a Team Lead And add 3 employees
This becomes unclear, as we no longer know where the employee is being added, it could be the team lead or the director.
Now let’s look at what we could do with variables:
Given the employees | Var | | director | | team lead| | report1 | | report2 | | report3 | And ‘director’ has reports ‘team lead’ And ‘team lead’ has reports ‘report1, report2, report3’
This is a lot more verbose, it is 10 lines versus the previous 3 lines. But there is a big difference, as these 3 steps can model any hierarchy, no matter how deep. And if we wanted to, we could make the first step implicit (creating employees once they are referred to by another step).
At the start, for instance, we could do the following:
Given the employees | Var | | director | | team lead | | report1 | | report2 | | report3 | And ‘director’ has reports ‘team lead’ And ‘team lead’ has reports ‘report1, report2, report3’ When ‘team lead’ retires Then ‘director’ manages ‘report1, report2, report3’
As you can see the “Then” verification step is very easy to re-use. We can refer to specific employees by name which allows us to do detailed verifications of specific points in the hierarchy. Not only that, now that the language is clear, there is no reason to open up the steps to see what exactly is happening behind the scenes.
As we refer to data entities by name, we can also treat them as variables; for instance, if we want to check the “totalReportsCount” and “directReportsCount” property we could say:
Given the employees | Var | | director | | team lead| | report1 | And ‘director’ has reports ‘team lead’ And ‘team lead’ has reports ‘report1’ When ‘team lead’ retires Then ‘director.totalReportsCount’ equals ‘1’ And ‘director.directReportsCount’ equals ‘1’
To implement this we would need to build a resolver, a class that knows about all the different objects. When the resolver is called it checks all the different repositories, in this case, employees, and asks for the variable by name, in this case, ‘director.’ When the resolver finds the variable it uses reflection to look for the property ‘totalReportsCount’ and it evaluates the expression. We now have the generic capability to validate variables and their properties.
Adding variables in the Gherkin allows your testers to create reusable steps with a minor increase to the infrastructure of the test framework. By using the resolver before evaluating a table you can even refer to variable properties inside of tables. And, naming the objects you deal with allows you to refer to them later on, making steps more generic and keeping the language clear and complete.
Meaningful Tests and Confidence
With this usage of variables in Gherkin, Cucumber remains an efficient and pragmatic language to use for your tests. Your development team, from the managers to the business analysts will be able to understand and gather value from the tests. And, as we all know, meaningful tests create confidence and prove the value in your quality assurance efforts.
If you enjoyed this article, please share!