BDD Series (3) — Gherkin. Anatomy of a feature file.

Manvendra P Singh
6 min readFeb 24, 2022

--

In previous post we had an overview of the Cucumber, Gherkin & feature file. Now let's see how to write test cases in feature files using Gherkin.

Anatomy of a feature-file

All non-blank lines in a feature file have to start with a valid Gherkin keyword. Some of them we discussed in the previous post. Here is the description of the main Gherkin keywords.

Feature:

The first Keyword in feature-file must be Feature, it must be followed by :

After Feature: cucumber ignores all the text and lines for processing until a line starting with either Scenario, Background, or Scenario Outline keyword is found. All the text in between is used only for reporting purposes.
The first line is used as the feature name, and the remaining lines (if present) are used as feature descriptions.

Scenario:

Scenario keyword must also be followed by : .
Any text after : in this line, is used for reporting purposes.

Steps:

“Steps” is not a Gherkin keyword but it's an integral concept.
Within a scenario, the keywords Given, When, Then, But and And are used to mention steps. These keywords are not followed by any : . Any text in the same line followed by these keywords is considered as a step.

The Cucumber engine looks for the step-definition files to understand what to do in these steps. Step-definition can be written in many programming languages as mentioned in the previous post. We will talk more about step-definition later here, first, let's look at the steps.

Let's take an example scenario of a web application where only the admin user should be able to view reports.

Scenario: Unauthorize admin reports access
Given website page "website-url" is open
And Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
But User should not see reports section

NOTE:
Cucumber is a BDD framework.

Tests should only be about the behavior of the system. Tests should not expose internal details about the system.

In the above example, instead of “enter user id and password” I mentioned, “User logs in”. It's left to the step-definition file to decide how a user logs in. Those internal details shouldn’t be exposed to someone who is reading or writing the scenario, as those are irrelevant to the behavior under test.

Given

The step mentioned in Given should be treated as a precondition for your test case. Do not start user interaction in Given. This step should just set up your test system to an initial state, so it can start executing test-related steps.

When

When is an action that is the essence of your test scenario?
Gherkin grammar doesn't stop you from having multiple When, but for clarity purposes, you should use only one when inside your scenario. Also, the steps in when should perform the main action that you meant to test.

Then

This is where you validate your outcome of Given and When actions.
Then is like assertions in your Junit tests. But unlike Junit, this assertion should be on some observable outcome of the system under test.

It should not be validating some change in resources or a process within the system. As we discussed in our previous posts, BDD is about “what the system is doing”, leaving aside the technical know-how of how it’s doing.

But, And

Ideally Given, When, Then are the only constructs a Scenario should have. However, as per good design, each step should do only one thing, so for a real-life scenario, you might end up with multiple Given and Then statements. This is where you replace those successive Given and Then with And and But. like we did in the above example.

Below is a syntactically valid but BAD way to write the above scenario without And and But

Scenario: Unauthorize admin reports access
Given website page "website-url" is open
Given Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
Then User should not see reports section

(*)

As we saw above, not all scenarios can be written with just Given , When , Then steps. So we use And and But to express our scenario in a more linguistic manner. But if you are getting a hard time expressing the steps with And and But you can use * in front of the step instead.

Scenario Outline:

This is used when we want to execute the same scenario multiple times with different data. As far as syntax is concerned there are only 3 differences from the above-discussed syntax.

  1. Use keyword Scenario Outline: instead of Scenario:
  2. Steps can have variables data stated as <variableName>
  3. An Example Table is used at the end of the scenario which has one header row matching the variableNames used in Steps and more rows for data.
    Each row is used for one scenario execution and values are separated by |
Scenario Outline: Check Item Type Filter
Given website page "website-url" is open
And Have a "random" user
And User logs in
When User search for item type "<itemType>"
Then System should show all "<itemType>" items

Examples:
| itemType |
| bad items |
| good items |
| expired items |

Background:

When we want to execute the same steps in all scenarios within a feature file. It's better to write those steps as Background: a rough comparison is like @BeforeEach annotation from Junit5.

Make sure what you put in the Background: is not related to the behavior of the scenario you are testing. So in the above example, the following can be used as Background

Background:
Given website page "website-url" is open
Scenario: Unauthorize admin reports access
Given Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
But User should not see reports section
Scenario Outline: Check Item Type Filter
Given Have a "random" user
And User logs in
When User search for item type <itemType>
Then System should show all <itemType> items

Examples:
| itemType |
| bad items |
| good items |
| expired items |

(#)

In any line of feature-file, If the first non-space character is #, that line is regarded as a code comment. Any text followed by a # is discarded

This was a brief overview of Gherkin grammar, now let's take a look at the Step Definition

Step Definition

All text followed by any one of these keywords Given, When, Then, But And & * is called step. Steps give a nice business meaning to a scenario. But the Cucumber engine needs to know what to do when it sees those steps. That is where step-definition comes into the picture.

  • Step definition can be written in one of many supported languages mentioned in the previous post. I personally am aware only of Java.
  • The developer needs to create one or preferably a few syntactically grouped .java files and add a java method for each step. This method is the step-definition. and it should have code to perform the required tasks for the step.
  • The dynamic values in steps (text covered between “ “ or <>), should be declared as method parameters in the step definition.
  • Eventually, Cucumber flattens the directory structure before running the tests. so you can place the java files anywhere, but for maintainability, try to have a meaningful package structure.
  • The data from Data Table can be passed as a collection parameter to step definition.
  • The data from the Example table is processed in one row per scenario, so it can be passed as a scalar value in the step definition.
  • Step-definition class can have instance variables to share states between steps. but make sure to clean up states after you are done.
public class HomePageSteps{UserCredentials userCredentials; 
HomePage homePage;
@Given("^Have a \"([^\"]*)\" user$")
public void getUser(String userType) {
if("random".userType){
userCredentials = userService.getCredentials(getRandomUSer());
}else if("non ADMIN".userType){
userCredentials = userService.getCredentials("User1");
}else if("ADMIN".userType){
userCredentials = userService.getCredentials("myAdmin");
}
}
When("^User search for item type \"([^\"]*)\"$")
public void searchItem(String itemType) {
homePage.searchItemByType(itemType);
}
}

This concludes our brief summary about the Cucumber, In the next post, we will discuss how to use Karate to do API testing.

--

--