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
| Placeholder | Matches in Gherkin | Java type |
|---|---|---|
{string} | Text in double quotes: "alice" | String (without quotes) |
{int} | An integer: 42 | int / Integer |
{float} | A decimal: 3.14 | float / Float |
{double} | A decimal: 3.14 | double / Double |
{long} | A large integer | long / Long |
{bigdecimal} | Precise decimal (currency) | BigDecimal |
{word} | A single unquoted word: submit | String |
{} | Anything — anonymous | String (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-31With 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 definitionThe @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 hasthe 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 explicitio.cucumber.java.en.Whenwith 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. @ParameterTypemethod 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.
- Open your
LoginSteps.javafrom Chapter 1. Find any step definition that has a literal email, password, or URL hardcoded in the annotation text. Parameterise it with{string}. - Update the matching Gherkin step to include the quoted value. Run the scenario — it should still pass.
- Create a custom
@ParameterTypefor"success|error|redirect"calledloginResult. Write a step definition@Then("the login result should be {loginResult}")and a matching Gherkin step. Confirm the parameter is captured correctly. - 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. - Stretch: write a
@ParameterTypethat converts an ISO date string ("2025-12-31") to aLocalDate. 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.