[EN] BDD with Cucumber & Java: Why your tests should finally tell a story

Julian | Mar 13, 2026 min read

For many it is probably already old hat or rather everyday life. Today there is an introduction to ‘Cucumber’.

Why actually cucumber? (And what is this BDD?)

We know the problem in classic everyday development: The business side writes requirements, the developers write code and in the end everyone realizes during the review that they have talked past each other. This is where Behavior Driven Development (BDD) comes into play.

BDD: The Common Language

BDD is not just a testing concept, but a method to improve communication between product owners, testers and developers. Instead of technical specifications, we write User Stories in a form that everyone can read. We define the behavior of the software from the user’s perspective before we write a single line of production code.

Cucumber’s place in the ecosystem

Cucumber is the tool that turns these readable texts (we call them features) into automated tests. It builds the bridge between human language and your test code.

The advantage: Your documentation is also your test set. If the documentation is out of date, the tests will fail. “Living Documentation” in its purest form.

Gherkin: The bridge between people and code

To help Cucumber understand what we expect from our software, we use a structured language called Gherkin. Gherkin is designed to be readable by business people, but at the same time offers enough structure to be processed automatically.

The anatomy of a scenario

A Gherkin document (usually a .feature file) consists of various keywords. The most important ones to start with are:

  • Feature: Describes the high-level functionality (e.g. “User Login”).
  • Scenario: A specific use case or test case (e.g. “Successful login with correct data”).
  • Given (Accepted): Describes the initial state or context. Where are we? What has already happened?
  • When: This is where the actual interaction takes place. What does the user do?
  • Then: The expected result. What should happen? What are we checking?
  • And / But: Auxiliary words to logically connect steps without disturbing readability by constantly repeating “Given” or “Then”.

A practical example

This is what the whole thing looks like in the editor:

Feature: Warenkorb-Funktionalität

  Scenario: Ein Produkt zum leeren Warenkorb hinzufügen
    Given ich befinde mich auf der Produktdetailseite von "Kaffee-Bohnen"
    When ich auf den Button "In den Warenkorb" klicke
    Then sollte die Anzahl der Artikel im Warenkorb "1" sein
    And mir sollte die Bestätigung "Produkt hinzugefügt" angezeigt werden

Why this structure? In projects, I often see teams get too technical in the Gherkin steps (e.g. “When I click on the div with ID #btn-123”). Avoid this! Gherkin is meant to describe the what, not the how. The technical implementation belongs in the code, not in the feature file.

Hands-on: Create the first feature file

Enough theory! Let’s integrate the first feature file into a project. For the whole thing to work, we need a clean folder structure and – very importantly – the support of our IDE.

Das Tooling: IntelliJ IDEA Plugins

If you use IntelliJ (which is the standard in the Java environment), you should make sure that two plugins are installed:

  1. Gherkin: Provides syntax highlighting of .feature files.
  2. Cucumber for Java: This is the “magician” in the background. It detects whether code already exists for a text step, lets you jump directly to the implementation using Ctrl + Click and helps you generate missing step definitions.

Where does the file belong?

In a standard Maven or Gradle project, we place our feature files under src/test/resources. A proven pattern is: src/test/resources/features/[featuresarea]/login.feature

Our first scenario

Create a file called login.feature and fill it with life. We take a classic example:

@UI @Login
Feature: Benutzer-Anmeldung
  Als registrierter Nutzer möchte ich mich einloggen,
  um auf meinen persönlichen Bereich zuzugreifen.

  Scenario: Erfolgreicher Login mit validen Daten
    Given ich bin auf der Login-Seite
    When ich gebe den Benutzernamen "julian" und das Passwort "geheim123" ein
    And ich klicke auf den Login-Button
    Then werde ich zum Dashboard weitergeleitet
    And ich sehe die Willkommensnachricht "Hallo Julian"

Tip: Pay attention to the tags (the words starting with @). With @UI or @Login you can later specifically run only certain tests. This saves time if your test suite eventually includes hundreds of scenarios.

Behind the Scenes: Step Definitions

The feature file is the “what”, the Step Definitions are the “how”. In Java we create simple classes in which we link the Gherkin steps with methods.

Cucumber uses annotations such as @Given, @When and @Then, which are matched with the text in your .feature file via Regular Expressions or the more modern Cucumber Expressions.

This is what the “glue code” looks like

Here is the implementation for our login scenario:

import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;
import static org.assertj.core.api.Assertions.assertThat;

public class LoginSteps {

    // Ein Mock oder ein Page Object für die eigentliche Logik
    private LoginPage loginPage = new LoginPage();

    @Given("ich bin auf der Login-Seite")
    public void ichBinAufDerLoginPage() {
        loginPage.open();
    }

    @When("ich gebe den Benutzernamen {string} und das Passwort {string} ein")
    public void ichGebeDatenEin(String user, String pass) {
        loginPage.enterCredentials(user, pass);
    }

    @When("ich klicke auf den Login-Button")
    public void ichKlickeLogin() {
        loginPage.clickLogin();
    }

    @Then("werde ich zum Dashboard weitergeleitet")
    public void checkDashboard() {
        assertThat(loginPage.isDashboardVisible()).isTrue();
    }

    @Then("ich sehe die Willkommensnachricht {string}")
    public void checkWelcomeMessage(String expectedMessage) {
        String actualMessage = loginPage.getWelcomeText();
        assertThat(actualMessage).isEqualTo(expectedMessage);
    }
}

What is happening technically here?

  1. Parameter Passing: Do you notice the {string} placeholders? Cucumber extracts the text from the quotes in your Gherkin file and passes it directly as an argument into your Java method. This makes your tests extremely reusable.
  2. The Bridge: IntelliJ will show you (if the plugins are installed) a small green icon or the Cucumber logo to the left of the method. So you know: The link between text and code is there.

Tip: Beware of writing all test logic (like Selenium clicks or API calls) directly into the step definition class. Use the Page Object Pattern. The step definition should only handle the orchestration - the details of how a button is found belong in a separate Page class. This keeps your code maintainable.

Best practices & pitfalls

Cucumber is a sharp knife: in the right hands it cuts perfectly, in the wrong hands it hurts. To prevent your test code from becoming a maintenance nightmare, here are my most important tips:

1. Write declarative instead of imperative

Write your Gherkin steps to describe what the user does, not how they technically do it.

  • Bad (Imperative): `When I type the text “admin” in the field with the ID “user” and click on the element “.submit-btn”.
  • Good (Declarative): When I log in with my administrator credentials

2. Cucumber is not a replacement for unit tests

A common mistake: trying to test everything with Cucumber. Cucumber tests usually run via the UI or API and are significantly slower than unit tests. Use Cucumber for happy paths and important business logic. It’s better to test the 50 different validation errors in a form with quick JUnit tests.

3. Avoid “Gherkin spaghetti”

If a scenario has 20 steps, no one reads it anymore. If you notice that your feature files are getting too long, use the keyword ‘Background’ for recurring setups or try to group steps together logically.

Tip: If the product owner doesn’t read your feature files, Cucumber is probably the wrong tool for your project. The greatest added value is the common language.

Conclusion

Cucumber and BDD are powerful tools to bridge the gap between business and IT. It’s not just about seeing green ticks in your pipeline, but making sure we’re building the right thing - in a way that everyone on the team understands.

You now have the tools to get started with Java and IntelliJ: clear Gherkin syntax, clean glue code and a focus on maintainable step definitions. Start small, write your first scenario and let the documentation work for you!