How to call a step from another step in Cucumber-JVM

14,343

Solution 1

This functionality is not supported in Cucumber-JVM. (Note that the Cucumber Backgrounder document you link in your question describes using Steps within Steps as "an anti-pattern")

Essentially, we believe that Cucumber is a collaboration tool and that Gherkin is not a programming language.

You can see a longer discussion of how we arrived at this decision here

Solution 2

To call steps within step definitions, inherit cuke4duke.Steps in java

import cuke4duke.StepMother;
import cuke4duke.Steps;
import cuke4duke.annotation.I18n.EN.When;

public class CallingSteps extends Steps {
    public CallingSteps(StepMother stepMother) {
        super(stepMother);
    }

    @When("^I call another step$")
    public void iCallAnotherStep() {
        Given("it is magic"); // This will call a step defined somewhere else.
    }
}

Example: https://github.com/cucumber-attic/cuke4duke/blob/master/examples/java/src/test/java/simple/CallingSteps.java

Note: cuke4duke support scala as well

Solution 3

Calling steps within steps is a terrible anti-pattern that can easily be replaced by something much simpler.

Instead of one step calling another step, have both steps call the same helper method.

If you apply this pattern with rigour you and up with

  • step definitions that are all just single calls to helper methods
  • a suite of helper methods that collectively provide a test-api

The art of elegantly implementing your Cucumber scenarios now becomes a known programming problem as all your functionality is now directly in code in your programming language rather than being in some restrictive construct specific to Cucumber.

You can now

  • refactor your helper methods to provide cleaner interaces
  • use parameters to give methods greater power
  • use naming to give all your calls greater clarity
  • use a helper method as an entry point to a suite of extra functionality
  • use delegation to move functionality out of helper methods and into test service objects ...

Providing this separation can be initially challenging if you are not a programmer or not experienced in the particular programming language in use. However once you get past this initial hurdle the code you can and should produce will be much easier to work with than the tangled mess that inevitably occurs with step nesting.

Share:
14,343
Eric Hartford
Author by

Eric Hartford

I am a software engineer working on RESTful web service development, Web UI development, and big data backends.

Updated on June 13, 2022

Comments

  • Eric Hartford
    Eric Hartford almost 2 years

    In Cucumber (the ruby version) you can easily call steps from other steps and thus build hierarchical libraries of steps making it easy to write the Gherkin feature specifications in the most generic terms.

    However it is not readily apparent how to do this in Cucumber-JVM and I have been unable to find documentation for it.

    Let me be clear I am not interested in calling the step implementation function directly because I don't want to have to know what its signature is, nor to change the call every time the implementation changes.

    Rather, I want to pass an arbitrary string that will go through the regex matcher and automatically find the matching step and execute it. Just as the engine runs all steps.

    simple example of what I would expect syntax to look like to define synonym "logout":

    When("user logs out") { () =>
      d.executeScript("logout();")
    }
    When("logout") { () =>
      Step("user logs out")
    }
    
  • Eric Hartford
    Eric Hartford almost 10 years
    Of course this means if I want to define that synonym I'd have to define the implementation in a named method and consume that method, and of course that'd need to be in its own .java file with 29 lines of imports and package declarations and class definitions etc etc etc. instead of the 2 lines in my example.
  • Jacob
    Jacob almost 10 years
    Yes. That's the Java programming language. And the decision not to support steps calling steps was made because we've seen the mess that often results from Gherkin being used as a programming language.
  • romulusnr
    romulusnr over 8 years
    There are other reasons why someone might want to call steps from other steps. Handling common synonyms, or combining multiple steps, perhaps from another step definition library, without having to know what the underlying function names. You identified a single bad usage of a potential feature, and decided to throw the baby out with the bathwater, an anti-user decision.
  • Jupiter
    Jupiter almost 4 years
    An additional, handy pattern exists: martinfowler.com/bliki/PageObject.html. The Page Objects. The idea is that you represent the various objects on your page that users can interact with as classes, which then forms your test API. The Page Objects can then hierarchically use (call) each other to abstract away details not relevant to a particular user action with a page object that is to be simulated.
  • diabolist
    diabolist almost 4 years
    Personally I think page objects are an anti-pattern when cuking. Cuking is about what you are doing Page Objects are about how you are doing something. Also the web is not about pages its about resources and representations. Behaviour exercises a particular representation of a resource. A page can have several different bits of behaviour on it, and a particular behaviour can take place on or via several different pages. Page objects just don't fit with that understanding.