Behaviour-Driven Development encourages you to start defining the scenarios that express the desired behaviour in a textual format, e.g.:
Given a stock of symbol STK1 and a threshold of 10.0 When the stock is traded at 5.0 Then the alert status should be OFF When the stock is traded at 11.0 Then the alert status should be ON
The textual scenario should use the language of the business domain and shield away as much as possible the details of the technical implementation. Also, it should be given a name that is expressive of the functionality that is being verified, i.e. trader_is_alerted_of_status.scenario.
The scenario should use a syntax compatible with the Grammar.
JBehave maps textual steps to Java methods via a CandidateSteps instance. The scenario writer need only extend the default implementation Steps, and provide annotated methods that match, by regex patterns, the textual steps:
public class TraderSteps extends Steps { 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") 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)); } }
Each step is annotated with one of the step annotations, each holding a regex pattern as value. The pattern is used to match the method in the Steps class with the appropriate parameters. The simplest default behaviour identifies arguments in the candidate step by the words prefixed by the $ character. More advanced parameter injection mechanisms are also supported by JBehave.
JBehave execute all the matched steps in the order in which they are found in the Scenario. It is up to the implementor of the Steps class to provide the logic to tie together the results of the execution of each step. This can be done by keeping state member variables in the Steps class or possibly by using a service API or other dependency.
In JBehave Core scenarios can be run in an automated way via a
one-to-one mapping to Java classes. The mechanism via which the textual
scenarios are resolved from a Java class is determined by the
implementation of the ScenarioNameResolver.
In our example, we need to create a file TraderIsAletedOfStatus.java
,
which maps to out textual scenario in same package.
The contract for a user-defined Java scenario is the following:
Must extend an instance of a RunnableScenario, such as JUnitScenario
Must provide a default constructor.
(Only when running via Maven) Must provide an additional constructor with a ClassLoader parameter.
Thus in our case the example Scenario would look like:
public class TraderIsAletedOfStatus extends JUnitScenario { public TraderIsAletedOfStatus() { this(Thread.currentThread().getContextClassLoader()); } public TraderIsAletedOfStatus(final ClassLoader classLoader) { super(new MostUsefulConfiguration() { public ScenarioDefiner forDefiningScenarios() { return new ClasspathScenarioDefiner(new UnderscoredCamelCaseResolver(".scenario"), new PatternScenarioParser(new PropertyBasedConfiguration()), classLoader); } }, new TraderSteps()); } }
Here we are configuring our textual scenario files to end with extension .scenario, by overriding the default behaviour of UnderscoredCamelCaseResolver which has no extension.