Tuesday, September 18, 2012

Getting Started With JBehave

What is JBehave?  According to it's website:  "JBehave is a [Java] framework for [doing] Behaviour-Driven Development."  (http://jbehave.org/)  Behaviour-Driven Development, if you are not already familiar with the term, is sort of like Test Driven Development only the customer is much more involved.  To paraphrase "The Cucumber Book" by Matt Wynne and Aslak Hellesoy: Behaviour Driven Development ensures you're building the right thing while Test Driven Development ensures that the thing works the way it's supposed to.  In other words, Behaviour-Driven Development is used to safe guard against spending huge amounts of resources on testing and developing a product that the customer might not even want.

Suppose you wanted to develop a Calculator program.  Most Calculators can perform Addition so let's write what JBehave calls a Story file for that particular feature.  Here's one I derived from http://cukes.info/ to get us started:


Narrative:
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers

Scenario: Summation of two numbers
Given I want to do Addition
And my first operand is 6
And my second operand is 2
When I execute the Operation
Then I should get 8 as my result


Notice that there are no leading white spaces on each line.  This isn't necessarily mandatory, but I think its good practice to do so as it ensures the file gets read correctly.

JBehave expects you to save your stories in plain text files that have a .story file extension.  For each story file that you have, JBehave expects you to implement a subclass of JUnitStory so that it can be run through JUnit. (Ivan Zlatev's article titled Java BDD with JBehave and Watij in Eclipse with JUnit posted on May 25, 2011)

For example given the following JUnitStory subclass implementation...


package features.addition;

import org.jbehave.core.junit.JUnitStory;

public class AdditionStory extends JUnitStory {
 // code …
}


...JBehave will look for the plain text file addition_story.story.

Next we need to map the Given-When-Then steps to code that actually implements them.  The following code, derived from JBehave's "Getting Started", does just that:


package features.addition;

import static org.jbehave.core.reporters.Format.CONSOLE;

import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryLoader;
import org.jbehave.core.junit.JUnitStory;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;

public class AdditionStory extends JUnitStory {
 @Override
 public Configuration configuration( ) {
  Configuration configuration = new MostUsefulConfiguration( );

  // Where to find the stories
  StoryLoader storyLoader;
  storyLoader = new LoadFromClasspath(this.getClass( ));

  configuration.useStoryLoader(storyLoader);

  // CONSOLE reporting
  StoryReporterBuilder storyReporterBuilder;
  storyReporterBuilder = new StoryReporterBuilder( );

  storyReporterBuilder.withDefaultFormats( );
  storyReporterBuilder.withFormats(CONSOLE);

  configuration.useStoryReporterBuilder(storyReporterBuilder);

  return configuration;
 }

 @Override
 public InjectableStepsFactory stepsFactory( ) {
  return new InstanceStepsFactory(configuration( ), new AdditionSteps( ));
 }
}


Here's where we will store our step definitions:


package features.addition;

import org.jbehave.core.steps.Steps;

public class AdditionSteps {
  // code ...
}


When we run the above AdditionStory, JBehave outputs some stuff along with the following annotated methods to help us get started.
 

@Given("I want to do Addition")
@Pending
public void givenIWantToDoAddition() {
  // PENDING
}

@Given("my first operand is 6")
@Pending
public void givenMyFirstOperandIs6() {
  // PENDING
}

@Given("my second operand is 2")
@Pending
public void givenMySecondOperandIs2() {
  // PENDING
}

@When("I execute the Operation")
@Pending
public void whenIExecuteTheOperation() {
  // PENDING
}

@Then("I should get 8 as my result")
@Pending
public void thenIShouldGet8AsMyResult() {
  // PENDING
}


I went ahead and implemented these methods.  Notice that I also removed the @Pending annotations.


package features.addition;

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;

import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;

public class AdditionSteps {

  private Addition addition;
  private int result;
 
  @Given("I want to do Addition")
  public void givenIWantToDoAddition() {
    addition = new Addition( );
  }

  @Given("my first operand is 6")
  public void givenMyFirstOperandIs6() {
    addition.setFirstOperand(6);
  }

  @Given("my second operand is 2")
  public void givenMySecondOperandIs2() {
    addition.setSecondOperand(2);
  }
 
  @When("I execute the Operation")
  public void whenIExecuteTheOperation() {
    result = addition.execute( );
  }

  @Then("I should get 8 as my result")
  public void thenIShouldGet8AsMyResult() {
    assertThat(result, is(equalTo(8)));
  }
}


And here's the corresponding Addition class:


package operations;

public class Addition { 
  private int firstOperand, secondOperand;

  public void setFirstOperand(int value){
    this.firstOperand = value;
  }
 
  public void setSecondOperand(int value){
    this.secondOperand = value;
  }
 
  public int execute( ){
    return firstOperand + secondOperand;
  }
}


Obviously there's a lot more that you can do with JBehave.  For example, there's a nifty page template you can use to keep track of your stories. (Click here to see an example).  The goal I had for this article was just to get you started using JBehave.  It should also be noted that you cannot change the font color of the Windows command prompt through Java.

2 comments:

  1. Can you post a view of you source tree?
    I can't figure out how all of this is organized in Eclipse?
    Is Addition in your project and Jbehave tests in their own project?
    Thanks

    ReplyDelete
    Replies
    1. I added a picture of how my project is structured.
      Note: I replaced the stuff package with features.addition and operations packages.

      Delete