Step Definitions with Parameters and Expressions

9 min read

You've written step definitions that call driver.get(url) and check URLs. But real scenarios involve variable data — usernames, prices, product names, quantities. This lesson covers Cucumber Expressions, the modern parameter syntax that extracts those values from Gherkin steps cleanly, plus the regex fallback for complex patterns.

Cucumber Expressions: the modern way

A Cucumber Expression is the text inside a @Given, @When, or @Then annotation. It can contain literal words and parameter type placeholders in curly braces. When Cucumber matches a Gherkin step against a step definition, it extracts the values at each placeholder and passes them as method parameters.

@Given("the user has {int} items in the cart")
public void userHasItemsInCart(int count) {
    cart.seed(count);
}
 
@When("the user searches for {string}")
public void userSearchesFor(String query) {
    searchPage.search(query);
}
 
@Then("the total price should be {double}")
public void priceShouldBe(double price) {
    assertEquals(price, orderPage.getTotal(), 0.01);
}
 
@When("the user clicks the {word} button")
public void userClicksButton(String buttonName) {
    page.clickButton(buttonName);
}

The Java method must have exactly the same number of parameters as there are placeholders in the annotation — and the types must match. Mismatch causes a CucumberException at startup, not at runtime, so you catch it immediately.

Built-in parameter types

PlaceholderMatches in GherkinJava type
{string}Text in double quotes: "alice"String (without quotes)
{int}An integer: 42int / Integer
{float}A decimal: 3.14float / Float
{double}A decimal: 3.14double / Double
{long}A large integerlong / Long
{bigdecimal}Precise decimal (currency)BigDecimal
{word}A single unquoted word: submitString
{}Anything — anonymousString (always)

The {string} placeholder strips the surrounding double quotes, so the Java String value is the bare content. {word} matches a single token with no spaces and no quotes — useful for button names, status values, HTTP verbs.

Use {bigdecimal} wherever monetary precision matters. {double} introduces floating-point rounding errors — a price of 9.99 stored as double is 9.990000000000001. BigDecimal avoids that entirely.

Custom parameter types

Sometimes your Gherkin uses domain values that aren't plain strings. A @ParameterType method teaches Cucumber how to convert the matched text into a typed value:

// In any class in the glue package
@ParameterType("admin|tester|viewer")
public String role(String role) {
    return role;   // could validate, log, or convert to an enum
}
 
@ParameterType("\\d{4}-\\d{2}-\\d{2}")
public LocalDate isoDate(String date) {
    return LocalDate.parse(date);
}

Now these work in Gherkin:

Given the user has role admin
When the user sets the expiry to 2025-12-31

With step definitions:

@Given("the user has role {role}")
public void userHasRole(String role) { ... }
 
@When("the user sets the expiry to {isoDate}")
public void setExpiry(LocalDate date) { ... }

Custom types improve readability — {role} in the annotation communicates intent more clearly than {word}, and the converter method can validate (throw on invalid input) or transform (return an enum).

Optional text and alternation

Optional text — words in parentheses are optional. The step definition matches with or without them:

@When("the user click(s) the {word} button")

Matches both When the user click the submit button and When the user clicks the submit button. Useful when your Gherkin authors inconsistently pluralise.

Alternation — a slash separates alternatives:

@Then("the order should be accepted/rejected")

Matches the order should be accepted or the order should be rejected. Combine with a {word} parameter when you need to capture which alternative matched.

Regular expressions (legacy but valid)

Before Cucumber Expressions existed, regex was the only option. It still works:

@When("^the user enters (.+) as username$")
public void enterUsername(String username) { ... }
 
@Then("^the (\\d+) results? should be displayed$")
public void verifyResultCount(int count) { ... }

Use regex when Cucumber Expressions can't express the pattern — very specific character classes, lookaheads, complex alternations. For everything else, Cucumber Expressions are cleaner and more readable.

Step reuse across feature files

A step definition exists once and serves every scenario that matches its pattern. You don't repeat implementation per feature file:

# login.feature
Given the user is on the login page
 
# registration.feature
Given the user is on the login page     ← same step definition
 
# password-reset.feature
Given the user is on the login page     ← same step definition

The @Given("the user is on the login page") method is called for all three. This is the design constraint that pushes you toward well-named, declarative steps — a specific-to-one-scenario step definition is a sign the Gherkin is too specific.

How Cucumber matches a step

Step 1 of 6

Parse step text

Cucumber reads the Gherkin step text: 'the user searches for "Laptop"'. The keyword (Given/When/Then/And) is stripped — only the text matters for matching.

⚠️ Common mistakes

  • Mixing {string} and unquoted text. {string} matches text in double quotes. If the Gherkin step has the user enters alice as username (no quotes), {string} won't match — use {word} for a single unquoted token or {} for anything. Mismatched quoting is the most common step-matching failure.
  • Capturing groups in regex conflicting with Cucumber Expressions. If you mix @When("the user clicks (the|a) button") using regex syntax inside what Cucumber parses as a Cucumber Expression, you get unexpected captures. Choose one syntax per annotation — regex requires the full ^...$ anchors or the explicit io.cucumber.java.en.When with a regex string starting with ^.
  • Too-specific step text. @When("the user enters alice@test.com as email") is only usable for that one email address. Parameterise with {string} and let Gherkin supply the value.
  • @ParameterType method not in the glue package. Custom parameter types must be in a class that's in the configured glue packages. If Cucumber doesn't scan the class, the type is unknown and matching fails.

🎯 Practice task

Replace hardcoded values in your step definitions with parameters. 35–45 minutes.

  1. Open your LoginSteps.java from Chapter 1. Find any step definition that has a literal email, password, or URL hardcoded in the annotation text. Parameterise it with {string}.
  2. Update the matching Gherkin step to include the quoted value. Run the scenario — it should still pass.
  3. Create a custom @ParameterType for "success|error|redirect" called loginResult. Write a step definition @Then("the login result should be {loginResult}") and a matching Gherkin step. Confirm the parameter is captured correctly.
  4. Write a step definition using optional text: @When("the user click(s) the {word} button"). Write two Gherkin steps — one with "clicks" and one with "click" — and confirm both match the same step definition.
  5. Stretch: write a @ParameterType that converts an ISO date string ("2025-12-31") to a LocalDate. Use it in a step definition and write a Gherkin step that passes a date. Assert the parsed date in the step body.

Next lesson: Cucumber hooks — Before, After, BeforeStep, and AfterStep for lifecycle management.

// tip to track lessons you complete and pick up where you left off across devices.