# gherkin + cucumber

Writing automated tests for software might feel like building infrastructure before you have a product. The upfront investment can seem substantial without obvious payoffs. But the long-term benefits to team health, velocity, and confidence dwarf the initial cost. Automated testing catches bugs before they reach users, enables continuous deployment, and makes it easier for developers to contribute to unfamiliar code.

Cucumber creates automated software tests through an elegant, readable format. While many product teams struggle to get automated testing off the ground—perhaps never hearing about tools like Cucumber—many of us have unknowingly worked with its core component: Gherkin.

Writing acceptance criteria in Gherkin form helps teams define and agree on what "done" means for the features they build. Despite its apparent simplicity, Gherkin is nuanced. The difference between well-written and poorly-written Gherkin often confuses newcomers to the language.

Gherkin's quirks make sense when viewed through the lens of automated Cucumber tests. This post explores how Gherkin and Cucumber work together, helping you use Gherkin more effectively. You'll learn how a complete Gherkin + Cucumber implementation functions and how building a library of well-written scenarios creates the foundation for automated testing.

## Gherkin

Gherkin is a Domain Specific Language for writing acceptance criteria with five main statements:

  1. Scenario — a label for the behavior you're describing
  2. Given — the beginning state of the scenario
  3. When — a specific action that the user takes
  4. Then — a testable outcome, usually caused by the action in When
  5. And — continues any of the other three operators

Together these statements describe all actions a user must take to perform a task and the results of those actions.

A real-world Gherkin example:

1Scenario: User clicks the link
2  Given I am on the homepage
3  When I click the provided link
4  Then I should see the link click confirmation

Or in general form:

1Scenario: Some determinable business situation
2  Given some precondition
3    And some other precondition
4  When some action by the actor
5    And some other action
6    And yet another action
7  Then some testable outcome is achieved
8    And something else we can check happens too

Product Managers typically write Gherkin acceptance criteria before feature development begins. Having acceptance criteria in an easy-to-read structure makes it easier for developers and designers to understand the intended user flow. This alone provides value, but represents only a fraction of well-structured Gherkin's potential. After all, many effective approaches to writing feature descriptions (like As a ___ I want to ___ so that ___) can improve communication.

These other approaches have their place and often complement Gherkin. However, once teams move beyond manual QA into automated testing, Gherkin's real value emerges. With some clever techniques, the English Gherkin scenarios we write can automatically translate into testable code. To understand this, let's examine Gherkin's counterpart: Cucumber.

## Cucumber

### How Cucumber reads Gherkin

Cucumber translates Gherkin scenarios to code using pattern matching technology called Regular Expressions (or Regex).

This allows Cucumber to scan your scenarios for Gherkin keywords (Scenario, Given, When, Then, and And) and the phrases that follow them. When Cucumber finds a phrase it recognizes, it translates that phrase into executable code using Step Definitions.

### Step definitions

Step definition files act like a foreign language dictionary. They give test suites a way to translate English scenario steps into executable code. Developers who build the feature typically write the step definitions.

Step definition files look like this:

1When(/^I go to the homepage$/) do
2  visit root_path
3end
4Then(/^I should see the welcome message$/) do
5  expect(page).to have_content("Hello Cucumber")
6end

The first statement says "any time you find the string 'I go to the homepage' then run the visit root_path function."

The second statement says "any time you find the string 'I should see the welcome message' then expect the current page to contain the text 'Hello Cucumber' somewhere."

Each step in a scenario should have a corresponding step definition so the automated test suite knows how to translate English into code. Over time you'll write hundreds of these step definitions, many reusable across your test suite (like the first step above).

Important note: Reusing functions only works if we use consistent phrasing for each action. If scenarios use both I go to the homepage and I visit the homepage interchangeably, we must maintain two separate step definitions for the same action. This duplicated code makes test suites harder to maintain and violates the DRY (don't repeat yourself) principle of software development.

As applications and test suites grow, step definitions and scenarios multiply. This can quickly become overwhelming. Feature files help organize test suites.

### Feature files

Feature files group Gherkin scenarios together to manage test suite complexity. Feature files function like a virtual checklist ensuring your software works. Beyond the scenarios needed to test a feature, Feature files include a short feature description and any business rules or additional information that clarifies what the feature does.

A feature file might look like this:

1Feature: Some terse yet descriptive text of what is desired
2  Textual description of the business value of this feature
3  Business rules that govern the scope of the feature
4  Any additional information that will make the feature easier to understand
5
6  Scenario: Some determinable business situation
7    Given some precondition
8      And some other precondition
9    When some action by the actor
10      And some other action
11      And yet another action
12    Then some testable outcome is achieved
13      And something else we can check happens too
14
15  Scenario: A different situation
16    ...

Applications can (and should) have many feature files describing how features work. These tests work together to provide an overview of your application's health.

## Output

Running your test suite on the command line with Cucumber produces output like this:

1$ cucumber -s
2Using the default profile...
3Feature: Hello Cucumber
4Scenario: User sees the welcome message
5  When I go to the login page
6  Then I should see the welcome message
7
81 scenario (1 passed)
92 steps (2 passed)
100m0.148s

Or for something more tangible:

1$ cucumber -s
2Using the default profile...
3Feature: Google Homepage Search
4Scenario: User sees the header
5  Given I'm on the homepage
6  Then I see the header
7Scenario: User can search with "Google Search"
8  Given I'm on the homepage
9  When I type "random page" into the search field
10  And I click the Google Search button
11  Then I go to the random page search results
12Scenario: User can search with "I'm Feeling Lucky"
13  Given I'm on the homepage
14  When I type "random page" into the search field
15  And I click the I'm Feeling Lucky button
16  Then I go to a random page
17Scenario: User can see the Terms and Conditions
18  ...
19
2015 scenarios (15 passed)
2187 Steps (87 passed)
220m3.141s

The output from running your test suite provides an immediate way to check your application's health. It shows where changes broke old functionality or where new functionality isn't working as designed. This makes it easy to identify and fix issues so you can ship with confidence.

### Wrapping up

Using Gherkin to write scenarios makes it simple to demonstrate the flows your product needs. Feature files help organize those flows into logical chunks. Cucumber scans those chunks and provides a live readout of which pieces of your software work and which don't.

A complete test suite where every feature has a feature file and set of scenarios is powerful. It makes catching bugs in new features easy, helps avoid introducing bugs in old features, and communicates progress with stakeholders. It automates some of the biggest delays between building a feature and getting it into users' hands.

Using Gherkin and Cucumber isn't the only way to build automated acceptance criteria testing, but it provides a structure that scales well. You can start writing Gherkin immediately and as your team matures and grows, add step files and automated testing with Cucumber. When used effectively, Cucumber and Gherkin give us a clear (and iterative!) path toward comprehensive automated testing.


Examples borrowed from Cucumber, Conductor, and SemaphoreCI.