Skip to content
Home / Skills / Bdd / Gherkin Scenarios
BD

Gherkin Scenarios

Bdd syntax v1.0.0

Gherkin Scenarios

Overview

Gherkin is a business-readable, domain-specific language for describing software behavior without detailing implementation. Using a structured syntax based on Given-When-Then patterns, Gherkin enables both humans and test automation frameworks to understand specifications. Scenarios written in Gherkin serve as executable specifications, living documentation, and automated acceptance tests. The language’s simplicity allows business stakeholders to write or review tests while maintaining technical precision for automation.

Effective Gherkin scenarios focus on business behavior, not technical implementation. They describe what the system should do from a user’s perspective, making them resilient to refactoring and valuable as documentation long after code is written.


Key Concepts

Gherkin Syntax Structure

# Feature file structure
Feature: High-level feature description
  Business context and value
  
  Background:
    Common preconditions for all scenarios
  
  Scenario: Specific behavior to test
    Given [precondition/context]
    And [additional context]
    When [action/event]
    And [additional action]
    Then [expected outcome]
    And [additional outcome]
    But [negative outcome]
  
  Scenario Outline: Parameterized test template
    Given [step with <parameter>]
    When [action with <parameter>]
    Then [outcome with <parameter>]
    
    Examples:
      | parameter | values |
      | value1    | data1  |
      | value2    | data2  |

Given-When-Then Pattern

StepPurposeExampleGuidelines
GivenSetup/Context”Given I am logged in”Describes the initial state
WhenAction/Event”When I submit the form”Single action that triggers behavior
ThenOutcome/Result”Then I should see confirmation”Observable result/side effect
And/ButContinuation”And I receive an email”Continue previous step type

Gherkin Keywords

Feature:           # High-level description (one per file)
Background:        # Common setup for all scenarios
Scenario:          # Single test case
Scenario Outline:  # Parameterized test template
Examples:          # Data table for Scenario Outline
Given:             # Precondition
When:              # Action
Then:              # Expected outcome
And:               # Continue previous step
But:               # Negative continuation
* :                # Universal step (any type)
# :               # Comment
@tag:              # Tag for organization/filtering
""":               # Multi-line string
| table |:         # Data table

Data Tables vs Examples

# Data Tables - Input to a single step
Given the following users exist:
  | username | email           | role  |
  | alice    | alice@test.com  | admin |
  | bob      | bob@test.com    | user  |

# Examples - Multiple scenario executions
Scenario Outline: Login with credentials
  When I login with <username> and <password>
  Then I should see <result>
  
  Examples:
    | username | password | result    |
    | admin    | secret   | Dashboard |
    | guest    | guest    | Error     |

Background vs Before Hook

# Background - Visible in feature file, part of specification
Background:
  Given the system is configured
  And test data is loaded

# Before Hook - Technical setup, not part of spec
# @Before (in step definitions)
# - Database cleanup
# - Test fixture creation
# - Mock server initialization

Best Practices

1. Write Declarative Scenarios, Not Imperative

Describe what happens, not how. Focus on business intent, not UI interactions.

2. Keep Scenarios Independent

Each scenario should run in isolation. No dependencies between scenarios.

3. Use Domain Language, Not Technical Jargon

Stakeholders should understand scenarios without technical knowledge.

4. One Behavior Per Scenario

Test a single business rule. Multiple assertions for same behavior are OK.

5. Make Scenarios Readable as Documentation

Scenarios should tell a story. Future readers should understand intent without code.


Code Examples

Example 1: Well-Structured Feature File

# File: src/test/resources/features/user-registration.feature

Feature: User Registration
  As a new customer
  I want to create an account
  So that I can make purchases and track orders
  
  Business Rule: Email addresses must be unique
  Business Rule: Passwords must be at least 8 characters

  Background:
    Given the registration system is available
    And no account exists for "john@example.com"

  # ✅ GOOD - Clear, focused scenario
  Scenario: Successfully register with valid details
    Given I am on the registration page
    When I register with the following details:
      | email              | password    | firstName | lastName |
      | john@example.com   | SecurePass1 | John      | Doe      |
    Then my account should be created
    And I should receive a welcome email at "john@example.com"
    And I should be logged in automatically

  # ✅ GOOD - Tests business rule clearly
  Scenario: Cannot register with existing email
    Given an account already exists for "john@example.com"
    When I attempt to register with email "john@example.com"
    Then I should see error "An account with this email already exists"
    And no new account should be created

  # ✅ GOOD - Scenario Outline for similar test cases
  Scenario Outline: Reject invalid password
    When I register with email "john@example.com" and password "<password>"
    Then I should see error "<error_message>"
    And no account should be created

    Examples: Too Short
      | password | error_message                           |
      | short    | Password must be at least 8 characters  |
      | 1234567  | Password must be at least 8 characters  |

    Examples: Missing Requirements
      | password      | error_message                        |
      | NoNumbers     | Password must contain at least 1 digit |
      | no-uppercase  | Password must contain uppercase letter |

# ❌ BAD - Imperative, UI-focused scenario
# Scenario: Register new user (BAD)
#   Given I open browser
#   And I navigate to "http://localhost:8080/register"
#   When I type "john@example.com" into field "email"
#   And I type "SecurePass1" into field "password"
#   And I type "SecurePass1" into field "confirmPassword"
#   And I type "John" into field "firstName"
#   And I type "Doe" into field "lastName"
#   And I click button "Submit"
#   Then I should see element with id "success-message"
#
# Problems:
# - Brittle (breaks when UI changes)
# - Technical details obscure business intent
# - Not readable by stakeholders
# - Coupling to implementation

Example 2: Data Tables - Inline Data

Feature: Order Management

  # ✅ GOOD - Data table for complex input
  Scenario: Create order with multiple items
    Given I am logged in as customer "C123"
    When I create an order with the following items:
      | product    | quantity | unitPrice |
      | Widget A   | 2        | 25.00     |
      | Gadget B   | 1        | 50.00     |
      | Tool C     | 3        | 10.00     |
    Then the order total should be $130.00
    And the order should contain 3 distinct items
    And the order status should be "PENDING"

  # ✅ GOOD - Vertical table for single entity
  Scenario: Update customer profile
    Given I am logged in as "john@example.com"
    When I update my profile:
      | firstName  | John              |
      | lastName   | Doe               |
      | phone      | 555-1234          |
      | address    | 123 Main St       |
      | city       | Springfield       |
      | zipCode    | 12345             |
    Then my profile should be updated
    And I should see confirmation "Profile saved successfully"

  # ❌ BAD - Unnecessary data table (overkill)
  # Scenario: Simple login (BAD)
  #   When I login with credentials:
  #     | username | password |
  #     | admin    | secret   |
  #   Then I should be logged in
  #
  # Better as:
  # When I login with username "admin" and password "secret"

Example 3: Scenario Outlines - DRY Principle

Feature: Shopping Cart Calculations

  # ✅ GOOD - Scenario Outline for calculation logic
  Scenario Outline: Calculate cart total with tax
    Given I have an empty cart
    When I add items totaling $<subtotal>
    And I select shipping to "<region>"
    Then my cart subtotal should be $<subtotal>
    And sales tax should be $<tax>
    And total should be $<total>

    Examples: US States
      | subtotal | region     | tax   | total  |
      | 100.00   | California | 8.75  | 108.75 |
      | 100.00   | Texas      | 6.25  | 106.25 |
      | 100.00   | Oregon     | 0.00  | 100.00 |

    Examples: International
      | subtotal | region  | tax   | total  |
      | 100.00   | Canada  | 13.00 | 113.00 |
      | 100.00   | UK      | 20.00 | 120.00 |

  # ✅ GOOD - Outline for permission testing
  Scenario Outline: User permissions vary by role
    Given I am logged in as a user with role "<role>"
    When I attempt to <action>
    Then the result should be "<result>"

    Examples: Admin Actions
      | role  | action              | result  |
      | admin | delete user         | success |
      | admin | view audit logs     | success |
      | admin | modify system config| success |

    Examples: Regular User Actions
      | role | action              | result   |
      | user | delete user         | forbidden|
      | user | view audit logs     | forbidden|
      | user | view own profile    | success  |

  # ❌ BAD - Scenario Outline for unrelated cases
  # Scenario Outline: Various system behaviors (BAD)
  #   When I do "<action>"
  #   Then result is "<result>"
  #   
  #   Examples:
  #     | action        | result    |
  #     | login         | dashboard |
  #     | add to cart   | cart page |
  #     | checkout      | payment   |
  #
  # Problem: Unrelated scenarios forced into template
  # Better: Separate scenarios for each behavior

Example 4: Background for Common Setup

Feature: Product Search

  # ✅ GOOD - Background for common preconditions
  Background: Product catalog exists
    Given the following products are in the catalog:
      | sku      | name          | category    | price  | inStock |
      | WDG-001  | Premium Widget| Electronics | 99.99  | true    |
      | GDG-002  | Super Gadget  | Electronics | 149.99 | true    |
      | TOL-003  | Basic Tool    | Tools       | 29.99  | true    |
      | TOL-004  | Pro Tool      | Tools       | 79.99  | false   |

  Scenario: Search by category
    When I search for category "Electronics"
    Then I should see 2 products
    And I should see "Premium Widget"
    And I should see "Super Gadget"

  Scenario: Search by price range
    When I search for products between $50 and $100
    Then I should see 2 products
    And results should include "Premium Widget"
    And results should include "Pro Tool"

  Scenario: Filter out of stock items
    When I search for category "Tools" with filter "inStock=true"
    Then I should see 1 product
    And I should see "Basic Tool"
    But I should not see "Pro Tool"

# ❌ BAD - Overusing Background
# Background: 
#   Given I open the browser
#   And I navigate to home page
#   And I click "Accept Cookies"
#   And I wait 2 seconds
#
# Problem: Technical details in Background
# Background should be business-focused, not UI steps

Example 5: Advanced Gherkin Patterns

Feature: Complex Order Processing

  # ✅ GOOD - Multi-line strings (Doc Strings)
  Scenario: Submit order with special instructions
    Given I have items in my cart
    When I submit order with delivery instructions:
      """
      Please leave package at back door.
      Ring doorbell twice.
      Do not deliver before 5 PM.
      Call if any issues: 555-1234
      """
    Then my order should be submitted
    And delivery instructions should be attached to order

  # ✅ GOOD - Tags for organization and filtering
  @critical @smoke @payment
  Scenario: Process credit card payment
    Given I have an order totaling $100.00
    When I pay with credit card:
      | number           | 4111111111111111 |
      | expiry           | 12/26           |
      | cvv              | 123             |
    Then payment should be successful
    And order status should be "PAID"

  # ✅ GOOD - Combining And/But for readability
  Scenario: Cancel order with refund
    Given I have a paid order
    And the order has not shipped
    When I request to cancel the order
    Then the order should be cancelled
    And I should receive a full refund
    But I should not receive a cancellation fee
    And I should receive cancellation confirmation email

  # ✅ GOOD - Using * for any step type (when type doesn't matter)
  @regression
  Scenario: Verify order confirmation details
    * an order exists with ID "ORD-12345"
    * I request order details for "ORD-12345"
    * I should see order total "$150.00"
    * I should see order status "CONFIRMED"
    * I should see 3 items in the order

  # ✅ GOOD - Comments for context (not executed)
  Scenario: Apply promotional discount
    # Business Rule: SUMMER23 promo gives 20% off orders over $100
    # Valid from June 1 - August 31, 2023
    Given I have an order totaling $150.00
    And today is "2023-07-15"
    When I apply promo code "SUMMER23"
    Then my discount should be $30.00
    And my total should be $120.00

  # ✅ GOOD - Testing error conditions
  @error-handling
  Scenario: Handle payment gateway timeout
    Given I have an order ready for payment
    And the payment gateway is unavailable
    When I attempt to pay with credit card
    Then I should see error "Payment processing temporarily unavailable"
    And my order should remain in "PENDING" status
    And I should be offered to retry or choose alternate payment

# ❌ BAD - Testing multiple independent behaviors
# Scenario: Complete user journey (BAD)
#   When I register new account
#   Then account is created
#   When I login
#   Then I see dashboard
#   When I add item to cart
#   Then cart has 1 item
#   When I checkout
#   Then order is placed
#
# Problem: Too much in one scenario
# Better: Separate scenarios for each behavior

Anti-Patterns

❌ Imperative Steps (UI-focused)

# ❌ BAD - Describes UI interactions
Scenario: Login (BAD)
  Given I am on "http://example.com/login"
  When I enter "john@example.com" into the field with id "email"
  And I enter "password123" into the field with id "password"
  And I click the button with text "Sign In"
  And I wait for 2 seconds
  Then I should see element with class "dashboard-container"

# ✅ GOOD - Describes business behavior
Scenario: Login (GOOD)
  Given I am a registered user
  When I login with valid credentials
  Then I should see my dashboard

❌ Incidental Details

# ❌ BAD - Too many irrelevant details
Scenario: Create order (BAD)
  Given a customer with ID 12345 named "John Doe"
  And customer email is "john@example.com"
  And customer created on "2023-01-15"
  And customer has address "123 Main St, Apt 4B, Springfield, IL, 62701"
  And a product with SKU "WDG-001"
  And product name is "Widget"
  And product price is $25.00
  When customer creates order for 2 units of product "WDG-001"
  Then order total is $50.00

# ✅ GOOD - Only relevant details
Scenario: Create order (GOOD)
  Given I am a registered customer
  And "Widget" costs $25.00
  When I order 2 units of "Widget"
  Then my order total should be $50.00

❌ Testing Implementation Details

# ❌ BAD - Coupled to database/API
Scenario: Update user (BAD)
  Given database table "users" has record with id=1
  When I send PUT request to "/api/users/1" with JSON:
    """
    {"firstName": "Jane", "lastName": "Doe"}
    """
  Then response status code should be 200
  And database table "users" record id=1 has firstName="Jane"

# ✅ GOOD - Business behavior
Scenario: Update user (GOOD)
  Given I am logged in as "John Doe"
  When I update my name to "Jane Doe"
  Then my profile should show name "Jane Doe"

Testing Strategies

Organizing Feature Files

# Organize by business capability/feature
features/
  ├── user-management/
  │   ├── registration.feature
  │   ├── login.feature
  │   └── profile.feature
  ├── shopping-cart/
  │   ├── add-items.feature
  │   ├── apply-discount.feature
  │   └── checkout.feature
  └── order-management/
      ├── create-order.feature
      ├── track-order.feature
      └── cancel-order.feature

# ✅ One feature per file
# ✅ Group related features in directories
# ✅ Use descriptive file names

Tagging Strategy

@smoke          # Critical path, run always
@regression     # Full test suite
@slow           # Tests that take > 1 second
@wip            # Work in progress, skip in CI
@bug-1234       # Regression test for specific bug
@api            # API-level tests
@ui             # UI-level tests
@critical       # Business-critical scenarios
@integration    # Integration tests

# Tag at feature level
@smoke @user-management
Feature: User Login

# Or at scenario level
  @critical @happy-path
  Scenario: Successful login

  @error-handling
  Scenario: Failed login

# Run specific tags
# mvn test -Dcucumber.filter.tags="@smoke"
# mvn test -Dcucumber.filter.tags="@regression and not @slow"

Step Definition Reusability

# Write generic step definitions that work across scenarios

# ✅ GOOD - Reusable across features
Given I am logged in as {string}
When I navigate to {string}
Then I should see {string}

# These steps can be used in any feature:
# - Given I am logged in as "admin@example.com"
# - When I navigate to "dashboard"
# - Then I should see "Welcome"

# ❌ BAD - Overly specific
Given I am logged in as admin user with email "admin@example.com" and password "secret"
When I click on the dashboard link in the top navigation bar
Then I should see the text "Welcome, Administrator" in the header

Maintaining Living Documentation

# Keep scenarios up-to-date as documentation

# ✅ Include business context
Feature: Discount Codes
  As a customer
  I want to apply discount codes
  So that I can save money on purchases
  
  Business Rules:
  - Only one discount per order
  - Expired codes cannot be used
  - Codes are case-insensitive

# ✅ Use tags to track status
@implemented @tested
Scenario: Apply percentage discount

@wip @future-release
Scenario: Apply discount with loyalty points

@bug-1234 @fixed
Scenario: Discount rounds correctly

# ✅ Link to external docs
Feature: Order Processing
  See: https://wiki.example.com/orders
  Jira: PROJ-123

References