Candidate Steps

JBehave uses annotations in the CandidateSteps instance to associate an executable Java method to a CandidateStep. Each candidate step corresponds to one Java method and to one StepType. A candidate step holds the regex pattern contained in the annotation value, which is used to do the matching with the textual steps in the scenario.

Let's look at a concrete example:

public class TraderSteps { // It does not have to extend Steps, but it could

    private Stock stock;

    @Given("a stock of symbol $symbol and a threshold of $threshold")
    public void aStock(String symbol, double threshold) {
        stock = new Stock(symbol, threshold);
    }

    @When("the stock is traded at $price")
    @Alias("the stock is sold at $price")
    public void theStockIsTradedAt(double price) {
        stock.tradeAt(price);
    }

    @Then("the alert status should be $status")
    public void theAlertStatusShouldBe(String status) {
        ensureThat(stock.getStatus().name(), equalTo(status));
    }

}

For each method annotated with one of the step annotations, a candidate step is created. Note that each method can supports aliases and a different candidate step is created for each alias.

So, given one or more instances of Steps classes, each containing a number of annotated methods, JBehave collects a list of candidate steps, which are then used to match the textual steps found in the scenarios being run. For each given StepType, the regex pattern must be unique.

Hence, the following two methods are allowed to have the same regex pattern, because they correspond to different step types:


    @Given("a stock is traded at $price")
    public void aStockWithPrice(double price) {
        // ...
    }

    @When("the stock is traded at $price")
    public void theStockIsTradedAt(double price) {
        // ...
    }

While the following would result in a runtime failure when running the scenario:


    @When("a stock is traded at $price")
    public void aStockWithPrice(double price) {
        // ...
    }

    @When("the stock is traded at $price")
    public void theStockIsTradedAt(double price) {
        // ...
    }

Note that in the example above TraderSteps is a POJO, i.e. it does not extend the Steps class. In this case, we need to use the StepsFactory to create CandidateSteps to associate to the RunnableStory class. The factory creates an instance of Steps which wraps the POJO instance. But, in addition to the the composition model, JBehave also supports the inheritance model, in which the steps class would simply extend Steps. The only difference is in how the steps are registered with the RunnableStory:

public class TraderStory extends JUnitStory {

    public TraderStory() {
        addSteps(new TraderSteps()); // if TraderSteps extends Steps
        addSteps(new StepsFactory().createCandidateSteps(new TraderSteps())); // if TraderSteps is a POJO
    }
}