An introduction to JBehave

JBehave is a BDD (for Behaviour Driven Development) framework, and a such it is used to map between stories expressed in natural language, and the underlying java code used to test these stories.

A concrete example of how this works.

1) First the story is written, usually following a given-when-then template.

Scenario: a trade with a positive price passes validation
Given a trade with a positive price
When the trade is validated
Then trade passes validation



2) Then a class is created which maps the text above to the the yet-to-be-written production code (since we follow a TDD approach the tests are written first, the production code later).


@Component
class TradeStep {

@Resource
private TradeService tradeService;

private Trade trade;

private boolean validationResult;

@Given("a trade with a positive price")
public void aTradeWithAPositivePrice() {
   trade = new Trade(1);
}

@When("the trade is validated")
public void theTradeIsValidated() {
   validationResult = tradeService.validate(trade);
}

@Then("trade passes validation")
public void tradePassesValidation() {
   assertTrue(validationResult);
}


3) Finally the code required to make this test pass is actually written. In the example above this would be when the domain object Trade and its associated service TradeService are implemented. Note that in this scenario the TradeService is a dependency injected by Spring.

public class Trade {

   int price;

   Trade (int price){
      this.price = price;
   }
}


import org.springframework.stereotype.Component;

@Component
public class TradeService {
   public boolean validate(Trade trade) {
      return (trade.price > 0);
   }
}


4) Last but not least – JBehave requires an entry point into the tests, a.k.a an Embedder.  This is a piece of code which indicates to JBehave where to look for the stories files, how to handle failures, which reports to output …etc… Each of these behaviours can be easily customized.

There are several embedders to choose from but in this instance we use a “SpringAnnotatedEmbeddedRunner” because it provides Spring based dependency injection.

   @RunWith(SpringAnnotatedEmbedderRunner.class)
    @UsingEmbedder(
            generateViewAfterStories = true,
            ignoreFailureInStories = false,
            ignoreFailureInView = false)

    @UsingSpring(resources={"spring-config.xml"})

    @Configure(
            storyReporterBuilder= JBehaveRunner.CustomReportBuilder.class ,
            pendingStepStrategy = FailingUponPendingStep.class
    )
   @UsingSteps(instances={TradeStep.class})
   public class JBehaveRunner extends InjectableEmbedder {

        protected java.util.List<String> storyPaths (){
            return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()), "*.story", "")   ;
        }


        @Test
        public void run() throws Throwable{
            injectedEmbedder().runStoriesAsPaths(storyPaths()) ;
        }

        public static class CustomReportBuilder extends StoryReporterBuilder {
            public CustomReportBuilder (){
                CrossReference crossReference = new CrossReference().withJsonOnly().withOutputAfterEachStory(true);

                this.
                        withDefaultFormats()
                        .withFailureTrace(true)
                        .withFormats(HTML, CONSOLE)
                        .withCrossReference(crossReference)
                        .withCodeLocation(codeLocationFromClass(this.getClass())) ;
            }
        }
    }

When JBehave runs a test report will be generated for each story. It will look like so if all goes well (all green !):

jbehave_pass

if something goes wrong instead the result will be:

jbehave_fails

Put together all of the JBehave reports will form a live documentation of the system. Any member of the team can check in realtime what is the expected behaviour of the system, without having to dig into the code. If JBehave is hooked into the continuous integration build, which is highly-recommended, these reports will never go out of date.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s