Gherkin & Cucumber — Complete Quick Reference
Gherkin Keywords
| Keyword | Purpose |
|---|---|
| Feature | Describes the functionality being tested; normally one Feature per .feature file |
| Scenario | Represents a single test case |
| Scenario Outline | Represents a data-driven test that runs once for each row in Examples |
| Examples | Provides test data for a Scenario Outline |
| Given | Defines the precondition or initial context |
| When | Defines the action being performed |
| Then | Defines the expected result |
| And | Continues the previous step type |
| But | Continues the previous step type with contrast/exception |
| Background | Contains common steps executed before every scenario in the Feature |
| Rule | Groups related scenarios around a specific business rule; available in Gherkin 6+ |
# |
Used to add comments |
Feature File Structure
A .feature file describes the behavior of an application using business-readable language.
@login @smoke
Feature: User Login
As a registered user
I want to log in
So that I can access my dashboard
Background:
Given the user is on the login page
@positive
Scenario: Login with valid credentials
When the user enters username "admin" and password "admin123"
And clicks the login button
Then the dashboard should be displayed
@negative
Scenario Outline: Login with invalid credentials
When the user enters username "<username>" and password "<password>"
And clicks the login button
Then the error message "<message>" should be displayed
Examples:
| username | password | message |
| admin | wrong | Invalid password |
| unknown | admin123 | User not found |
| | admin123 | Username is required |
Scenario vs Scenario Outline ⭐
| Type | Execution |
|---|---|
| Scenario | Executes once |
| Scenario Outline | Executes once for every row in the Examples table |
For example, the above Scenario Outline executes 3 times because there are 3 rows of test data.
Data Tables
Data Tables are useful when you need to pass multiple pieces of structured data to a step.
Feature File
Scenario: Create multiple users
Given the following users exist:
| name | email | role |
| Nav | nav@test.com | admin |
| Alex | alex@test.com | user |
Step Definition
@Given("the following users exist:")
public void createUsers(DataTable table) {
List<Map<String, String>> rows =
table.asMaps(String.class, String.class);
for (Map<String, String> row : rows) {
System.out.println(
row.get("name") + " - " + row.get("role")
);
}
}
Common DataTable Conversion
List<Map<String, String>> rows =
table.asMaps(String.class, String.class);
This converts the table into a list of maps.
For example:
row.get("name")
row.get("email")
row.get("role")
Doc Strings
Doc Strings are used when you need to pass multi-line text to a step.
A common use case is passing a JSON request body.
Feature File
Scenario: Create user through API
When the user sends the following request body:
"""
{
"id": 1,
"name": "Nav"
}
"""
Step Definition
@When("the user sends the following request body:")
public void sendRequestBody(String requestBody) {
System.out.println(requestBody);
}
Step Definitions ⭐
Step Definitions connect Gherkin steps with Java automation code.
The important rule is:
Step Definitions should call Page Object methods. Selenium code should remain inside the Page Objects.
Example
@Given("the user is on the login page")
public void userOnLoginPage() {
driver.get("https://example.com/login");
}
Cucumber Expressions
Cucumber Expressions allow dynamic values to be passed from feature files.
@When("the user enters username {string} and password {string}")
public void enterCredentials(String user, String pass) {
loginPage.login(user, pass);
}
The Feature File:
When the user enters username "admin" and password "admin123"
passes:
user = admin
pass = admin123
Expected Result
@Then("the dashboard should be displayed")
public void dashboardDisplayed() {
Assert.assertTrue(
dashboardPage.isDisplayed()
);
}
Cucumber Expression Parameters
| Expression | Matches |
|---|---|
{string} |
Quoted string |
{int} |
Integer |
{float} |
Decimal number |
{word} |
Single word |
{} |
Anonymous parameter; accepts any type |
Example
@When("the user enters {string}")
public void enterText(String text) {
System.out.println(text);
}
@When("the user enters OTP {int}")
public void enterOtp(int otp) {
System.out.println(otp);
}
@When("the user enters amount {float}")
public void enterAmount(float amount) {
System.out.println(amount);
}
Regular Expression Alternative
Instead of Cucumber Expressions, you can use regular expressions.
@When("^the user clicks the \"([^\"]*)\" button$")
public void clickButton(String button) {
System.out.println("Clicked: " + button);
}
For new projects, Cucumber Expressions are generally easier to read and maintain.
Step Definition Best Practice ⭐
❌ Avoid this
@When("the user enters username {string}")
public void enterUsername(String username) {
driver.findElement(
By.id("username")
).sendKeys(username);
}
Here, Selenium implementation is directly inside the step definition.
✅ Prefer this
@When("the user enters username {string}")
public void enterUsername(String username) {
loginPage.enterUsername(username);
}
Page Object:
public void enterUsername(String username) {
driver.findElement(
By.id("username")
).sendKeys(username);
}
Recommended Architecture
Feature File
↓
Step Definition
↓
Page Object
↓
Selenium WebDriver
↓
Application
This keeps the framework clean and maintainable.
Hooks
Hooks are used to execute setup and cleanup code before or after scenarios.
@Before
Runs before every scenario.
@Before
public void setUp() {
driver = new ChromeDriver();
}
@After
Runs after every scenario.
@After
public void tearDown(Scenario scenario) {
if (scenario.isFailed()) {
byte[] screenshot =
((TakesScreenshot) driver)
.getScreenshotAs(OutputType.BYTES);
scenario.attach(
screenshot,
"image/png",
"failure"
);
}
driver.quit();
}
Tagged Hooks
You can execute a hook only for scenarios having a particular tag.
@Before("@smoke")
public void smokeSetup() {
System.out.println("Smoke test setup");
}
This hook runs only for:
@smoke
Scenario: Login test
@BeforeStep and @AfterStep
These hooks execute around every individual step.
@BeforeStep
public void beforeStep() {
System.out.println("Before step");
}
@AfterStep
public void afterStep() {
System.out.println("After step");
}
Hook Execution Order
@Before
↓
Background
↓
Given
↓
When
↓
Then
↓
@After
If @BeforeStep / @AfterStep are used:
@Before
↓
Background
↓
@BeforeStep
↓
Step
↓
@AfterStep
↓
@BeforeStep
↓
Step
↓
@AfterStep
↓
@After
Tags
Tags allow you to categorize and selectively execute scenarios.
@smoke @regression
Scenario: User login
You can also tag an entire Feature:
@smoke
Feature: User Login
The tag will apply to the scenarios inside that Feature.
Common Tag Expressions
Run smoke tests:
--tags "@smoke"
Run scenarios having both tags:
--tags "@smoke and @regression"
Run scenarios having either tag:
--tags "@smoke or @regression"
Exclude WIP scenarios:
--tags "not @wip"
Combined expression:
--tags "@regression and not @slow"
Cucumber Runner ⭐
Cucumber can be integrated with JUnit or TestNG.
JUnit Runner
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
glue = "stepdefinitions",
tags = "@smoke",
plugin = {
"pretty",
"html:target/cucumber-report.html",
"json:target/cucumber.json"
},
monochrome = true,
dryRun = false
)
public class TestRunner {
}
TestNG
For TestNG-based frameworks:
public class TestRunner
extends AbstractTestNGCucumberTests {
}
You can also configure Cucumber options using the appropriate Cucumber/TestNG setup.
@CucumberOptions
| Option | Purpose |
|---|---|
features |
Specifies the location of .feature files |
glue |
Specifies the package containing Step Definitions and Hooks |
tags |
Selects scenarios based on tags |
plugin |
Configures reporting/output plugins |
monochrome |
Makes console output easier to read |
dryRun |
Checks whether all steps have matching step definitions |
Example
@CucumberOptions(
features = "src/test/resources/features",
glue = "stepdefinitions",
tags = "@smoke",
plugin = {
"pretty",
"html:target/cucumber-report.html",
"json:target/cucumber.json"
},
monochrome = true,
dryRun = false
)
dryRun ⭐
dryRun is useful for checking missing step definitions.
dryRun = true
dryRun = true
Cucumber checks whether every Gherkin step has a matching Step Definition without actually executing the test.
dryRun = false
dryRun = false
The test executes normally.
Easy Interview Answer
dryRun = trueis used to validate whether all feature-file steps have corresponding step definitions without executing the actual test steps.
Cucumber Reports
Common plugins include:
plugin = {
"pretty",
"html:target/cucumber-report.html",
"json:target/cucumber.json"
}
pretty
Provides readable console output.
html
Generates an HTML report.
json
Generates JSON output that can be consumed by reporting tools or CI pipelines.
Parallel Execution ⭐
With TestNG, Cucumber scenarios can be executed in parallel using a parallel Data Provider.
Example:
@Override
@DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
Runner:
public class TestRunner
extends AbstractTestNGCucumberTests {
@Override
@DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}
Important
For parallel execution, your WebDriver must be thread-safe.
A common approach is:
private static ThreadLocal<WebDriver> driver =
new ThreadLocal<>();
This prevents different parallel tests from sharing the same WebDriver instance.
Recommended Project Structure
A clean Cucumber + Selenium framework can look like this:
src
├── test
│ ├── java
│ │ ├── runners
│ │ │ └── TestRunner.java
│ │ │
│ │ ├── stepdefinitions
│ │ │ └── LoginSteps.java
│ │ │
│ │ ├── pages
│ │ │ └── LoginPage.java
│ │ │
│ │ └── utils
│ │ ├── Hooks.java
│ │ └── DriverFactory.java
│ │
│ └── resources
│ └── features
│ └── login.feature
Responsibility of Each Layer
| Layer | Responsibility |
|---|---|
features |
Business-readable test scenarios |
stepdefinitions |
Connect Gherkin to Java code |
pages |
Selenium locators and UI actions |
utils |
Driver, configuration, reusable utilities |
runners |
Cucumber execution/configuration |
Hooks |
Setup, teardown, screenshots, etc. |
Common Cucumber Errors
| Error | Cause | Solution |
|---|---|---|
| Undefined step | No matching Step Definition exists | Check the step text and glue path |
| Ambiguous step | More than one Step Definition matches the same step | Remove or modify the duplicate matching definitions |
| Duplicate step definition | Same step definition exists multiple times | Keep only one matching definition |
| NullPointerException on driver | Driver was not initialized or is not shared correctly | Check @Before, DriverFactory, and driver lifecycle |
| Steps not detected | Incorrect glue package |
Verify the package path |
| Feature not found | Incorrect Feature path | Verify the features location |
| Scenario not running | Incorrect tag expression | Check the tags configuration |
| Browser closes unexpectedly | Incorrect driver lifecycle | Check @After and DriverFactory |
Complete Execution Flow ⭐
The overall Cucumber + Selenium execution flow is:
.feature file
↓
Feature / Scenario
↓
Cucumber Runner
↓
Tag Filtering
↓
@Before Hook
↓
Background
↓
Step Definition
↓
Page Object
↓
Selenium WebDriver
↓
Web Application
↓
Expected Result
↓
@After Hook
↓
Cucumber Report
21. Most Important Cucumber Interview Points ⭐
Scenario vs Scenario Outline
A Scenario executes once, while a Scenario Outline executes once for every row in the
Examplestable.
Background
Backgroundcontains common preconditions that execute before every scenario in the Feature.
DataTable
DataTableis used to pass structured tabular data from a Feature File to a Step Definition.
Doc String
A Doc String is used to pass multi-line text, such as JSON, XML, or request bodies, from a Feature File to a Step Definition.
Hooks
Hooks execute setup and teardown logic before or after scenarios or individual steps.
Tags
Tags are used to categorize scenarios and selectively execute tests, such as smoke, regression, or sanity tests.
Glue
gluetells Cucumber where to find Step Definitions and Hooks.
Dry Run
dryRun = truevalidates whether Feature File steps have corresponding Step Definitions without executing the tests.
Page Object Model
Step Definitions should contain business-level actions and delegate UI interactions to Page Objects rather than directly using Selenium.
Parallel Execution
Cucumber scenarios can be executed in parallel with TestNG using a parallel Data Provider, provided the WebDriver and test state are thread-safe.
Go Deeper
- Complete BDD & Cucumber Guide — the full path
- Top 15 BDD Questions — interview prep
- BDD vs TDD — the comparison
- Hybrid Framework With POM — the framework