Lesson 11: Gherkin Language

Learning Objectives

By the end of this lesson, you will be able to:

  1. Write well-structured feature files using correct Gherkin syntax including features, scenarios, and step definitions
  2. Apply Gherkin keywords effectively (Given, When, Then, And, But, Background) to create clear, readable specifications
  3. Use advanced Gherkin features including data tables, scenario outlines, and tags to reduce duplication and improve maintainability
  4. Organize feature files using best practices for structure, naming, and modularity that scale with project complexity
  5. Identify and fix common Gherkin anti-patterns that reduce scenario clarity and maintainability

Introduction

Gherkin is the language used to write BDD scenarios—a business-readable, domain-specific language that lets you describe software behavior without detailing how that behavior is implemented. Created as part of the Cucumber project, Gherkin has become the standard language for BDD across many frameworks and programming languages [1].

The genius of Gherkin lies in its simplicity. With just a handful of keywords (Feature, Scenario, Given, When, Then), you can describe complex behavior in a way that both business stakeholders and technical team members understand. This shared language eliminates the ambiguity that plagues traditional requirements documents while creating executable specifications that verify behavior automatically [2].

Gherkin’s power extends beyond basic scenarios. Data tables enable testing with multiple data sets without duplication. Scenario outlines create parameterized tests from examples. Tags organize and filter scenarios for different execution contexts. These features transform Gherkin from a simple specification language into a comprehensive tool for behavior documentation and test automation [3].

However, Gherkin’s simplicity can be deceptive. Writing clear, maintainable Gherkin requires discipline and understanding of best practices. Poorly written scenarios become brittle, hard to understand, and expensive to maintain. This lesson teaches you not just Gherkin syntax but the principles behind writing effective specifications that remain valuable throughout a project’s lifetime [4].


Core Content

Gherkin Syntax Fundamentals

Gherkin uses a structure of keywords followed by text. The text after keywords is not parsed by Gherkin—it’s free-form text for human readers [1].

Basic Structure:

# Comments start with hash
Feature: Brief description of the feature
  More detailed description can go here
  over multiple lines

  Background:
    Steps that run before each scenario

  Scenario: Description of this specific scenario
    Given some initial context
    When an action occurs
    Then verify the outcome

Core Keywords:

  • Feature: Container for related scenarios, describes high-level functionality
  • Scenario: Single test case describing specific behavior
  • Given: Preconditions or initial state
  • When: Action or event that triggers behavior
  • Then: Expected outcome or result
  • And/But: Additional steps of the same type (readability)
  • Background: Steps that run before every scenario in the feature

Feature Block:

Feature: User Authentication
  As a registered user
  I want to log in to my account
  So that I can access personalized features

  This feature covers:
  - Login with email and password
  - Account lockout after failed attempts
  - Password reset functionality

The feature description provides context but isn’t executed. Use it to explain the feature’s purpose and scope.

Scenario Structure:

Scenario: Successful login with valid credentials
  Given I am a registered user with email "[email protected]"
  And my password is "SecurePass123"
  When I enter my credentials on the login page
  And I click the "Log In" button
  Then I should see the dashboard
  And I should see a welcome message
  But I should not see the login form

Step Keywords:

All step keywords (Given, When, Then, And, But) are functionally equivalent to Gherkin—the distinction is for human readability:

# These work identically
Given user is logged in
And cart has items
And payment method is set

# Could be written as:
Given user is logged in
Given cart has items
Given payment method is set

# But "And" reads more naturally

Background: Shared Setup

Background runs before each scenario in a feature, reducing duplication [1].

Feature: Shopping Cart Management

  Background:
    Given I am logged in as "[email protected]"
    And I am on the products page

  Scenario: Add single item to cart
    When I click "Add to Cart" for "Laptop"
    Then my cart should contain 1 item
    And the item should be "Laptop"

  Scenario: Add multiple items to cart
    When I add "Laptop" to my cart
    And I add "Mouse" to my cart
    Then my cart should contain 2 items

  Scenario: Remove item from cart
    Given I have "Laptop" in my cart
    When I remove "Laptop" from my cart
    Then my cart should be empty

Each scenario runs with the Background steps first:

  1. Log in
  2. Navigate to products page
  3. Execute scenario steps

When to Use Background:

  • Good: Setup common to all scenarios (login, navigation, test data)
  • Avoid: Background steps that only apply to some scenarios
  • Avoid: Complex backgrounds that make scenarios hard to understand
# Bad - overly complex background
Background:
  Given the system has the following users:
    | email           | role  | status |
    | [email protected]  | admin | active |
    | [email protected]   | user  | active |
  And the system has the following products:
    | name   | price | stock |
    | Laptop | 999   | 50    |
    | Mouse  | 29    | 100   |
  And the payment gateway is configured
  And email service is running
  # Too much! Most scenarios don't need all this

# Good - minimal background
Background:
  Given I am logged in as a standard user

Data Tables: Structured Data

Data tables pass lists of data to step definitions [1].

Simple Lists:

Scenario: Add multiple items to cart
  Given I have the following items:
    | Laptop |
    | Mouse  |
    | Keyboard |
  When I calculate the total
  Then I should see 3 items in my cart

Tables with Headers:

Scenario: Calculate order total with multiple items
  Given I have the following items in my cart:
    | product  | price | quantity |
    | Laptop   | 999   | 1        |
    | Mouse    | 29    | 2        |
    | Keyboard | 79    | 1        |
  When I proceed to checkout
  Then my subtotal should be $1,136

Vertical Tables (Property Lists):

Scenario: Create user account
  Given I register with the following details:
    | field     | value             |
    | email     | [email protected]  |
    | password  | SecurePass123     |
    | firstName | John              |
    | lastName  | Doe               |
  When my account is created
  Then I should receive a welcome email

Step Implementation Example:

@given('I have the following items in my cart')
def step_impl(context):
    context.cart = ShoppingCart()
    for row in context.table:
        product = row['product']
        price = Decimal(row['price'])
        quantity = int(row['quantity'])
        context.cart.add_item(product, price, quantity)

Scenario Outline: Parameterized Tests

Scenario outlines run the same scenario multiple times with different data [1].

Basic Scenario Outline:

Scenario Outline: Login with different credentials
  Given I am on the login page
  When I enter email "<email>"
  And I enter password "<password>"
  Then I should see "<outcome>"

  Examples:
    | email                | password      | outcome                    |
    | [email protected]    | CorrectPass1  | Dashboard                  |
    | [email protected]  | WrongPass     | Invalid email or password  |
    | [email protected]    | WrongPass     | Invalid email or password  |
    | [email protected]   | CorrectPass1  | Account locked             |

This creates 4 separate scenarios, one for each row in Examples.

Multiple Example Tables:

Scenario Outline: Apply discount based on customer tier
  Given I am a "<tier>" customer
  And my cart total is $<amount>
  When I proceed to checkout
  Then my discount should be $<discount>

  Examples: Standard customers
    | tier     | amount | discount |
    | bronze   | 100    | 5        |
    | silver   | 100    | 10       |
    | gold     | 100    | 20       |

  Examples: Premium customers
    | tier     | amount | discount |
    | platinum | 100    | 25       |
    | diamond  | 100    | 30       |

When to Use Scenario Outlines:

# Good - same behavior, different data
Scenario Outline: Validate email format
  When I enter email "<email>"
  Then validation should "<result>"

  Examples:
    | email              | result |
    | [email protected]   | pass   |
    | invalid            | fail   |
    | user@              | fail   |
    | @example.com       | fail   |

# Bad - different behaviors, forced into one outline
Scenario Outline: User actions
  When I perform "<action>"
  Then I see "<result>"

  Examples:
    | action        | result            |
    | login         | dashboard         |
    | view_profile  | profile_page      |
    | logout        | login_page        |
  # These are different behaviors, should be separate scenarios!

Tags: Organization and Filtering

Tags enable organizing and selectively executing scenarios [3].

Basic Tags:

@authentication @critical
Feature: User Login

  @smoke @fast
  Scenario: Successful login
    Given valid user credentials
    When I log in
    Then I should see the dashboard

  @security @slow
  Scenario: Account lockout after failed attempts
    Given I have attempted login 5 times with wrong password
    When I attempt to login again
    Then I should see "Account locked"

Running Tagged Scenarios:

# Run scenarios with specific tag
behave --tags=@smoke

# Run scenarios with any of multiple tags (OR)
behave --tags=@critical --tags=@security

# Run scenarios with all tags (AND)
behave --tags=@authentication,@critical

# Exclude scenarios with tag
behave --tags=~@slow

# Complex expressions
behave --tags=@critical --tags=~@wip
# Runs critical scenarios that are not work-in-progress

Common Tag Conventions:

# Execution speed
@fast     # Quick tests (< 1 second)
@slow     # Longer tests (> 5 seconds)

# Test level
@unit           # Unit-level behavior
@integration    # Integration tests
@e2e           # End-to-end tests

# Priority
@critical    # Must always pass
@important   # High priority
@nice_to_have # Low priority

# Status
@wip         # Work in progress (skip in CI)
@manual      # Manual test (not automated)
@automated   # Fully automated
@flaky       # Known to be unreliable (needs fixing)

# Functional area
@authentication
@shopping_cart
@payment
@reporting

# Environment
@requires_staging  # Only runs in staging
@production_safe   # Safe to run against production

Feature-Level Tags:

@shopping @critical
Feature: Shopping Cart

  @smoke
  Scenario: Add item to empty cart
    # Inherits @shopping and @critical from feature
    # Also has @smoke

Scenario Organization Best Practices

One Feature, One File:

features/
├── authentication/
│   ├── login.feature
│   ├── registration.feature
│   ├── password_reset.feature
│   └── two_factor_auth.feature
├── shopping/
│   ├── cart.feature
│   ├── checkout.feature
│   ├── payment.feature
│   └── discounts.feature
└── account/
    ├── profile.feature
    ├── order_history.feature
    └── preferences.feature

Feature File Structure:

# Descriptive file name: user_registration.feature

@registration @authentication
Feature: User Registration
  As a new visitor
  I want to create an account
  So that I can access personalized features

  # Rules document business logic
  Rules:
    - Email must be unique
    - Password must be at least 8 characters
    - Account requires email verification

  Background:
    Given I am on the registration page

  # Happy path first
  @smoke @critical
  Scenario: Successful registration with valid data
    When I register with valid details
    Then I should see "Registration successful"
    And I should receive a verification email

  # Then alternatives and edge cases
  Scenario: Registration fails with duplicate email
    Given a user exists with email "[email protected]"
    When I attempt to register with email "[email protected]"
    Then I should see "Email already registered"

  Scenario: Registration fails with weak password
    When I attempt to register with password "weak"
    Then I should see "Password must be at least 8 characters"

  @security
  Scenario: Registration requires email verification
    Given I have registered but not verified my email
    When I attempt to log in
    Then I should see "Please verify your email first"

Writing Clear Step Text

Use Domain Language:

# Bad - technical implementation
Given the UserRepository contains a record with id=123
When the AuthService.authenticate() is invoked
Then the JWT token should be generated

# Good - business language
Given I am a registered user
When I log in with valid credentials
Then I should have access to my account

Be Specific:

# Bad - vague
Given some products exist
When I search for something
Then I should see results

# Good - concrete
Given the following products exist:
  | name   | category    | price |
  | Laptop | Electronics | 999   |
  | Mouse  | Electronics | 29    |
When I search for "Laptop"
Then I should see 1 search result
And the result should be "Laptop"

Avoid Implementation Details:

# Bad - specifies HOW
Given I navigate to URL "/login"
And I fill in the field with id "email" with "[email protected]"
And I fill in the field with id "password" with "pass123"
And I click the button with class "btn-submit"

# Good - specifies WHAT
Given I am on the login page
When I log in as "[email protected]" with password "pass123"

Keep Steps Atomic:

# Bad - compound step
When I add a laptop to cart and proceed to checkout and enter payment details

# Good - separate steps
When I add a laptop to cart
And I proceed to checkout
And I enter payment details

Common Pitfalls

Pitfall 1: Incidental Details

Including unnecessary details makes scenarios brittle and hard to read.

# Bad - too many incidental details
Scenario: User updates profile
  Given I am on the profile page
  And the "First Name" field contains "John"
  And the "Last Name" field contains "Doe"
  And the "Phone" field contains "555-1234"
  And the "Address" field contains "123 Main St"
  And the "City" field contains "Springfield"
  When I change "Last Name" to "Smith"
  And I click "Save"
  Then I should see "Profile updated"
  And the "Last Name" field should contain "Smith"

# Good - focused on what matters
Scenario: User updates profile
  Given I have a profile with last name "Doe"
  When I change my last name to "Smith"
  Then my profile should show last name "Smith"

Best Practice: Include only details relevant to the scenario’s purpose [2].

Pitfall 2: UI-Coupled Steps

Steps that reference UI elements break when UI changes.

# Bad - coupled to UI
When I click the button with id "submit-btn"
Then I should see text in div class "success-message"

# Good - behavior-focused
When I submit the form
Then I should see a success message

Best Practice: Describe user intentions and outcomes, not UI mechanics [4].

Pitfall 3: Scenario Interdependence

Scenarios that depend on each other create fragile test suites.

# Bad - scenarios depend on each other
Scenario: Create user account
  When I register as "[email protected]"
  Then my account should be created

Scenario: Login with new account
  # Depends on previous scenario!
  When I log in as "[email protected]"
  Then I should see the dashboard

Best Practice: Each scenario must be independently executable. Use Background or explicit Given steps to set up needed state [3].

Pitfall 4: Testing Multiple Behaviors

One scenario testing multiple unrelated behaviors makes failures ambiguous.

# Bad - multiple behaviors
Scenario: User account management
  Given I am logged in
  When I update my profile
  Then my profile should be updated
  When I change my password
  Then my password should be changed
  When I enable two-factor auth
  Then two-factor auth should be enabled

# Good - separate scenarios
Scenario: Update user profile
  Given I am logged in
  When I update my profile
  Then my profile should be updated

Scenario: Change password
  Given I am logged in
  When I change my password
  Then my password should be changed

Scenario: Enable two-factor authentication
  Given I am logged in
  When I enable two-factor auth
  Then two-factor auth should be enabled

Best Practice: One scenario, one behavior [2].


Summary

Gherkin is a business-readable language for writing BDD scenarios that serve as both specifications and automated tests. Its simple syntax—features, scenarios, and Given-When-Then steps—enables clear communication between technical and non-technical stakeholders.

Basic syntax uses keywords (Feature, Scenario, Given, When, Then) followed by free-form text. Given establishes context, When describes actions, Then verifies outcomes. And/But improve readability for multiple steps of the same type.

Background provides shared setup for all scenarios in a feature, reducing duplication. Use backgrounds for common preconditions, but keep them simple—complex backgrounds make scenarios hard to understand.

Data tables pass structured data to steps, enabling tests with multiple data points. Use tables with headers for clarity, and consider vertical tables (property lists) for single entities with many attributes.

Scenario outlines create parameterized tests by running the same scenario with different data from Examples tables. Use outlines when testing the same behavior with multiple inputs, not for forcing different behaviors into one template.

Tags organize scenarios for selective execution. Use tags for execution speed (@fast, @slow), test level (@unit, @integration), priority (@critical), status (@wip), and functional areas (@authentication). Run specific tags to focus test execution.

Organization best practices include one feature per file, clear directory structure by functional area, rules to document business logic, and presenting happy path scenarios before edge cases. Good organization makes feature files navigable and maintainable.

Clear step text uses domain language, specifies concrete examples, avoids implementation details, and keeps steps atomic. Steps should describe what users do and see, not how the system implements it.

Common pitfalls include incidental details (include only relevant information), UI-coupled steps (describe behavior, not UI mechanics), scenario interdependence (each scenario must be independent), and testing multiple behaviors (one scenario, one behavior).

Well-written Gherkin creates specifications that remain valuable throughout a project’s lifetime—understandable by all stakeholders, executable as tests, and serving as accurate documentation that evolves with the system.


Practice Quiz

Question 1: Your team writes this Gherkin scenario. What’s wrong with it, and how would you improve it?

Scenario: Checkout
  Given I am on page "/products"
  When I click element with id "add-to-cart-btn"
  And I click link with text "Cart"
  And I fill in textbox id "name" with "John Doe"
  And I fill in textbox id "card" with "4111111111111111"
  And I select "USA" from dropdown id "country"
  And I click button class "submit-payment"
  Then I should see text in div class "order-confirmation"

Answer: Multiple problems:

Issues:

  1. UI-coupled steps - references HTML elements (id, class)
  2. Implementation details - specifies HOW (click element, fill textbox)
  3. Incidental details - includes specific values not relevant to behavior
  4. Generic title - “Checkout” doesn’t describe specific behavior
  5. No clear behavior - unclear what’s being tested

Fixed version:

Scenario: Customer completes purchase with credit card
  Given I have items in my shopping cart
  When I proceed to checkout
  And I enter my shipping information
  And I pay with a valid credit card
  Then I should see order confirmation
  And I should receive a confirmation email

Further improvements with data tables:

@payment @critical
Scenario: Complete purchase with credit card
  Given I have the following items in my cart:
    | product | price |
    | Laptop  | 999   |
  When I checkout with the following details:
    | field          | value              |
    | name           | John Doe           |
    | cardNumber     | 4111111111111111   |
    | shippingCountry| USA                |
  Then I should see "Order confirmed"
  And my order total should be $999
  And I should receive an order confirmation email

This version focuses on behavior (what the user accomplishes), uses domain language (checkout, pay, order confirmation), and avoids implementation details (HTML elements, button clicks) [2][4].

Question 2: When should you use a Scenario Outline instead of multiple separate scenarios?

Answer: Use Scenario Outlines when testing the same behavior with different data. DON’T use them to force different behaviors into one template.

Good use - same behavior, different data:

Scenario Outline: Validate email format
  When I enter email "<email>"
  Then validation should "<result>"
  And I should see "<message>"

  Examples:
    | email              | result | message                    |
    | [email protected]   | pass   | Valid email                |
    | invalid            | fail   | Must include @ symbol      |
    | user@              | fail   | Must include domain        |
    | @example.com       | fail   | Must include username      |
    | user@example       | fail   | Must include domain suffix |

All examples test the same behavior (email validation) with different inputs.

Bad use - different behaviors forced together:

# DON'T DO THIS
Scenario Outline: User operations
  When I "<action>"
  Then I see "<result>"

  Examples:
    | action           | result          |
    | log in           | dashboard       |
    | view profile     | profile page    |
    | update settings  | settings saved  |
    | log out          | login page      |

These are different behaviors (login, view, update, logout), not the same behavior with different data. They should be separate scenarios.

Rule of thumb:

  • Use Scenario Outline: Testing validation rules, calculations with different values, same user journey with different data
  • Use separate scenarios: Different user actions, different features, different behaviors [1][3]

Question 3: Your feature file has this Background section. What problems might this cause?

Background:
  Given the following users exist:
    | email           | role  | tier     |
    | [email protected]  | admin | platinum |
    | [email protected]  | user  | gold     |
    | [email protected]  | user  | bronze   |
  And the following products exist:
    | name     | category    | price | stock |
    | Laptop   | Electronics | 999   | 10    |
    | Mouse    | Electronics | 29    | 50    |
    | Keyboard | Electronics | 79    | 30    |
  And the payment gateway is configured
  And the email service is running
  And the inventory service is running

Answer: This background is too complex and creates unnecessary dependencies.

Problems:

  1. Unnecessary setup - Most scenarios don’t need all this data
  2. Slow execution - Creates extensive test data before every scenario
  3. Unclear dependencies - Hard to tell what each scenario actually needs
  4. Difficult to debug - When something fails, is it the background or scenario?
  5. Tight coupling - All scenarios must work with this exact data

Fixed approach:

Option 1: Minimal background

Background:
  Given I am logged in as a standard user
  # Only what EVERY scenario truly needs

Option 2: Scenario-specific setup

# No background - each scenario sets up what it needs

Scenario: Add item to cart
  Given I am logged in
  And a product "Laptop" exists with price $999
  When I add "Laptop" to my cart
  Then my cart should contain 1 item

Scenario: Apply discount code
  Given I am a gold tier customer
  And I have items worth $100 in my cart
  When I apply discount code "SAVE10"
  Then my discount should be $10

Option 3: Background with common context only

Background:
  Given I am on the products page
  And I am logged in

# Each scenario adds its specific needs
Scenario: Search for product
  Given products exist in multiple categories
  When I search for "Laptop"
  ...

Guideline: Background should only include setup that every single scenario in the feature needs. If only some scenarios need it, put it in those scenarios [1][2].

Question 4: You’re writing Gherkin for a complex discount calculation system. Should you include the calculation formula in the scenario?

Answer: Yes, if the calculation IS the behavior you’re specifying. The key is focusing on behavior, not implementation.

Good - specifies business rule:

@calculation @critical
Scenario: Calculate volume discount for large orders
  Given the unit price is $100
  And the volume discount tiers are:
    | quantity | discount |
    | 10-49    | 5%       |
    | 50-99    | 10%      |
    | 100+     | 15%      |
  When I order 75 units
  Then the subtotal should be $7,500  # 75 × $100
  And the discount should be $750     # 10% of $7,500
  And the total should be $6,750      # $7,500 - $750

This is good because:

  • It documents the business rule (volume discount tiers)
  • It shows concrete examples with calculations
  • It verifies expected behavior with specific numbers
  • Business stakeholders can verify the logic

Bad - specifies technical implementation:

# DON'T DO THIS
Scenario: Calculate discount
  Given the DiscountCalculator class is instantiated
  When the calculateDiscount() method is called with order
  Then the method should iterate through discount_tiers array
  And apply the matching tier's percentage using multiply operator
  And return a DiscountResult object

This is bad because:

  • It describes HOW the code works internally
  • It’s coupled to implementation (class names, method names)
  • It breaks when you refactor
  • Non-technical stakeholders can’t understand it

Rule: Include calculations/logic when they represent business rules. Avoid describing technical implementation [2][4].

Question 5: Your project has 500+ scenarios. How should you organize them with tags to make them manageable?

Answer: Use a multi-dimensional tagging strategy covering different concerns:

@authentication @api @fast @critical
Feature: API Authentication

  @smoke @happy_path
  Scenario: Successful API authentication with valid token
    # Tags: authentication, api, fast, critical, smoke, happy_path

  @security @rate_limiting @slow
  Scenario: API blocks requests after rate limit exceeded
    # Tags: authentication, api, slow, critical, security, rate_limiting

@shopping @ui @integration
Feature: Shopping Cart

  @smoke @fast
  Scenario: Add item to empty cart
    # Tags: shopping, ui, integration, smoke, fast

  @payment @slow @requires_test_data
  Scenario: Complete checkout with multiple items
    # Tags: shopping, ui, integration, payment, slow, requires_test_data

Tag dimensions:

1. Functional area (what feature)

@authentication @shopping @payment @user_management @reporting

2. Technical layer (where it runs)

@api @ui @database @unit @integration @e2e

3. Execution speed (how long)

@fast      # < 1 second
@medium    # 1-5 seconds
@slow      # > 5 seconds

4. Priority (how important)

@critical   # Must always pass
@important  # High priority
@optional   # Nice to have

5. Test suite (when to run)

@smoke       # Quick confidence check (run always)
@regression  # Full regression (run before release)
@nightly     # Extensive tests (run overnight)

6. Status (implementation state)

@wip         # Work in progress (skip in CI)
@manual      # Not yet automated
@flaky       # Known to be unreliable (needs fixing)

Running strategies:

# During development (seconds)
behave --tags=@fast --tags=~@wip

# Before commit (minutes)
behave --tags=@critical --tags=@important

# CI smoke tests (2-3 minutes)
behave --tags=@smoke

# Full CI build (10-20 minutes)
behave --tags=@regression --tags=~@slow

# Nightly comprehensive (hours)
behave --tags=@nightly

# Feature-specific (development)
behave --tags=@shopping,@fast
# Only fast shopping scenarios

# Security audit
behave --tags=@security

# API-only tests
behave --tags=@api --tags=~@ui

Documentation:

Create tags.md explaining your tag strategy:

# Tag Conventions

## Functional Areas
- @authentication - Login, registration, password reset
- @shopping - Cart, products, search
- @payment - Checkout, payment processing

## Execution
- @smoke - Quick validation (run always)
- @critical - Must pass before release
- @fast - Under 1 second

## Status
- @wip - Skip in CI
- @flaky - Needs investigation

This multi-dimensional approach enables running exactly the scenarios you need for any context [3].


References

[1] Cucumber Documentation. (2024). Gherkin Reference. URL: https://cucumber.io/courses/gherkin/reference/, Quote: “Gherkin is a Business Readable, Domain Specific Language that lets you describe software’s behavior without detailing how that behavior is implemented. Gherkin uses a set of special keywords (Feature, Scenario, Given, When, Then) to give structure and meaning to executable specifications. The text following these keywords is not parsed by Gherkin—it’s free-form text for human readers.”

[2] Adzic, G. (2011). Specification by Example: How Successful Teams Deliver the Right Software. Manning Publications. URL: https://www.manning.com/books/specification-by-example, Quote: “Good scenarios focus on business rules and behavior, not implementation details. Avoid coupling scenarios to UI elements, technical APIs, or internal architecture. Scenarios should describe what users accomplish and what outcomes they observe, not how the system implements those outcomes. This keeps specifications maintainable when implementation changes.”

[3] Wynne, M., & Hellesoy, A. (2017). The Cucumber Book: Behaviour-Driven Development for Testers and Developers (2nd Edition). Pragmatic Bookshelf. URL: https://pragprog.com/titles/hwcuc2/the-cucumber-book-second-edition/, Quote: “Tags provide a powerful way to organize and filter scenarios. Use tags for functional areas, execution speed, priority, and status. Multi-dimensional tagging enables running exactly the scenarios you need: smoke tests during development, critical tests before commits, comprehensive suites in CI. Each scenario can have multiple tags serving different purposes.”

[4] Smart, J. F. (2014). BDD in Action: Behavior-Driven Development for the Whole Software Lifecycle. Manning Publications. URL: https://www.manning.com/books/bdd-in-action, Quote: “Effective Gherkin scenarios avoid incidental details—information not relevant to the behavior being tested. Include only what matters for understanding and verifying the scenario. Extra details make scenarios brittle (they break when irrelevant aspects change) and hard to read (readers must figure out what’s important). Focus scenarios on their core purpose: specifying one behavior clearly.”