JBehave uses method annotations in Java classes to associate an executable Java method to a StepCandidate. Each step candidate corresponds to one Java method and to one StepType. A step candidate holds the regex pattern contained in the annotation value, which is used to do the matching with the textual steps in the scenarios.
Let's look at a concrete example:
public class TraderSteps { // Look, Ma', I'm just a POJO private Stock stock; @Given ( "a stock of symbol $symbol and a threshold of $threshold" ) public void stock(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 step candidate is created. Note that each method can supports aliases and a different step candidate is created for each alias.
So, given one or more steps class instances, each containing one or more annotated methods, JBehave collects a list of step candidates, 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 ( "the stock is traded at $price" ) public void theStockWithPrice( double price) { // ... } @When ( "the stock is traded at $price" ) public void theStockIsTradedAt( double price) { // ... } |
By contrast, the following would result in a runtime failure when running the scenario:
@When ( "the stock is traded at $price" ) public void theStockWithPrice( 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 need to extend any JBehave class. JBehave provides the InjectableStepsFactory as a factory to create from these POJO steps instances the CandidateSteps it needs to extract the step candidates. The InstanceStepsFactory takes each steps instance provided by the user and wraps it in a Steps instance, which is the default implementation of CandidateSteps:
@RunWith (JUnitReportingRunner. class ) public class TraderStory extends JUnitStory { @Override public InjectableStepsFactory stepsFactory() { return new InstanceStepsFactory(configuration(), new TraderSteps( new TradingService()), new AndSteps(), new CalendarSteps(), new PriorityMatchingSteps(), new SandpitSteps(), new SearchSteps(), new BeforeAfterSteps()); } } |