We saw earlier that each Cucumber Scenario in a Feature file consists of steps which are normal English sentences preceded by Gherkin Keywords Given, When, Then, And, But.

Step Definitions are the methods/ functions (sometimes containing Expressions) which connect to one or more Gherkin steps. When we write Gherkin steps, our program code need to understand and interpret the steps. Step Definitions help with that interpretation.

Let us consider the below Gherkin step that we presented earlier:

Scenario: FirstApplication opens successfully in Desktop Chrome
Given user opens the Chrome browser in desktop


The part “user opens the Chrome browser in desktop” of the step will match to the following Step Definition:

package hellocucumber;

import cucumber.api.java.en.Given;

public class StepDefinition {

@Given("^user opens the Chrome browser in desktop$")
public void user_opens_Chrome_browser_in_desktop() {
    System.out.println(“Chrome Browser opened successfully in Desktop.”);
}

Cucumber basically performs four steps one by one:

  • It matches a step against a step definition
  • It gathers any capture groups or variables or expressions
  • It passes them to the method of the step definition
  • It executes the steps

All step definitions are loaded and defined before Cucumber starts to run the Feature file. Once the execution begins, for each step, Cucumber will check for a corresponding step definition with a matching expression. Once found, it will pass all the capture groups and variables from the expressions as method arguments.

EXPRESSIONS

A Step Definition can have two types of Expressions:
1) Regular Expressions
2) Cucumber Expressions

The expressions are used to link a Gherkin step to a Step Definition. If a Regular Expression is used in the Step, then each matching capture group will be passed as a parameter to the method of the step definition. For Example, if we use a Regex \”([^\”]*)\” in the step definition.

@Given(“^user opens the Chrome browser in \”([^\”]*)\”$”) and use the step
Given user opens the Chrome browser in “desktop”, then the word “desktop” will be passed as a String parameter(i.e. deviceType) to the below Step Definition method:

public void user_opens_Chrome_browser_in(String deviceType)

This removes the need to write separate step definitions for similar scenario steps. We can use another step like below without creating a new step definition:
Given user opens the Chrome browser in “mobile device”

If you are using Cucumber Expressions, then the step and step definition would look like
Step: Given user opens the Chrome browser in “desktop”
Step Definition: @Given(“^user opens the Chrome browser in {string}$”)

Where, {string} is the parameter type. The other parameter types of Cucumber Expressions are {int}, {float}, {word}, {string} and {}.

Remember, the number of parameters in the Step Definition method has to match the number of expressions (Regular Expression/ Cucumber Expression) used in the step definition.

DATA TABLE
The simplest way to pass a list of parameters to a step definition is to use a data table. The values get passed in a List format automatically by Cucumber. Take an example of the below step:

Given the following cities
|Melbourne|
|New York   |
|London       |

The step definition would look like:

@Given(“^the following cities$”)
public void the_following_cities(List<String> cities){
}

HOOKS AND TAGS

Hooks are code blocks which run at specific moments in the Cucumber Execution Life Cycle. Typically these are used to perform some initial setup and final tear down activities. To get more control of the Cucumber hooks, we can use Tagged Hooks. The hooks can be declared in any of the classes. In Cucumber, there is no concept of Global Hooks and hooks that can run only once based on some condition. Let’s discuss more about the hooks. Following are the Cucumber hooks:

  • Before
  • After
  • BeforeStep
  • AfterStep

Before
The Before hook runs before the first step of each Scenario. You can also specify order if you are using multiple Before hooks.

@Before(order=1)
public void setUp1(){
// Some code here
}
@Before(order=2)
public void setUp2(){
// Some code here
}

Here, setUp1 will run first and then setUp2 will run.

After
The After hook runs after the last step of each Scenario. You may or may not pass the optional parameter “Scenario scenario”. This parameter can be used to get different information related to the scenario that has been executed. You can also specify order if you are using multiple After hooks.

@After(order=1)
public void tearDown1(Scenario scenario){
// Some code here
}
@After(order=2)
public void tearDown2(Scenario scenario){
// Some code here
}

Here, tearDown2 will run first and then tearDown1 will run.

BeforeStep and AfterStep
Code inside the BeforeStep and AfterStep hooks will run before and after each step inside the scenario respectively.

@BeforeStep
public void stepInitialization(){
// Some code here
}
@AfterStep
public void stepCleaning(){
// Some code here
}

TAGGED HOOKS

We can also select hooks according to specific Tags used in the scenario. To run a tagged hook only for certain scenarios, we can associate a Before or After hook with a Tag Expression. For example:

@After(“@FirstApplicationFeature”)
public void tearDown(Scenario scenario){
// Some code here
}

Tags are used to organize features and scenarios. A Feature, Scenario, Scenario Outline and Examples can contain multiple tags separated by whitespaces. Tags cannot be placed on top of Background and Steps.Tags mainly serve two purposes:

  • Running a subset of scenarios
  • Scoping hooks to a subset of scenarios

Let’s now see some examples:

@FirstApplicationFeature
Feature: Testing the FirstApplication

@Scenario1
Scenario: FirstApplication opens successfully in Desktop Chrome
  Given user opens the Chrome browser in desktop
  When user enters the application URL and searches
  Then the application gets opened successfully.

@Scenario2
Scenario: FirstApplication opens successfully in Mobile Web
  Given user opens the Chrome browser in mobile device
  When user enters the application URL and searches
  Then the application gets opened successfully.

Here, @FirstApplicationFeature is the tag at the Feature level and the tags @Scenario1 and @Scenario2 are at the Scenario level. The tags follow Inheritance principle which means that tags specified at Feature level is applicable for Scenario, Scenario Outline and Examples and tags specified at Scenario Outline level is applicable to Examples as well.

To perform Tag-based execution, we can use the Tag Expressions (along with parenthesis as optional). The Tag Expressions based on the above example can be:
@Scenario1 -> Only scenario tagged with @Scenario1 will run
@Scenario1 and @Scenario2 -> Scenarios tagged with both @Scenario1 and @Scenario2 will run
@Scenario1 or @Scenario2 -> Scenarios tagged with either of @Scenario1 or @Scenario2 will run
not @Scenario1 -> Scenario/ Features under all the tags except @Scenario1 will run

Credits:
https://cucumber.io/docs/cucumber/