Stories with easyb

BDD principles support the notion of stories quite nicely-- you can think of a story as narrative between a stakeholder and development (almost like a use case). In short, think of a story as a description of a requirement, which has an associated benefit and criteria for validation.

Stories can be made up of scenarios that group specifications. The specifications are essential-- they are essentially steps that are friendly to read. They are:

  • Given (a context)
  • When (something happens)
  • Then (something else happens)

Stories in action

The default convention for stories in easyb is to place each story in a file ending with MyStory.story. So if you have story regarding shipping calculations, for example, you'd have a file named ShippingCalculations.story.

The code below shows a story in easyb in action-- the code has two scenarios which reside in a story file named EmptyStack.story.


import org.disco.easyb.bdd.stack.Stack

scenario "null is pushed onto empty stack", {
  given "an empty stack",{
    stack = new Stack()
  }

  when "null is pushed", {
    pushnull = {
      stack.push(null)
    }
  }

  then "an exception should be thrown", {
    ensureThrows(RuntimeException){
      pushnull()
    }
  }

  and "then the stack should still be empty", {
    stack.empty.shouldBe true
  }
}


scenario "pop is called on empty stack", {
  given "an empty stack",{
    stack = new Stack()
  }

  when "pop is called", {
    popnull = {
      stack.pop()
    }
  }

  then "an exception should be thrown", {
    ensureThrows(RuntimeException){
      popnull()
    }
  }
  
  and "then the stack should still be empty", {
      stack.empty.shouldBe true
    }

}

Does it not convey the intention clearly? Of course it does!! It's so easy too.

Take notice of multiple scenarios in that file, each with their own set of givens,whens and thens all coming together to create a story.

Pending stories and scenarios

easyb makes it easy to create stories with no coding so that you can come back to fill in the implementation later.

scenario "customers should receive discounts", {
 given "a shopping cart with 3 items"
 when "a user checks out"
 then "they should receive a 10% discount"
}

Note how the above scenario has no code-- it's simply just the text of the scenario-- easyb will mark any unimplemented feature as a pending specification.

Printing stories

It wouldn't be fair to only let the developers see this beautiful story now would it? We didn't think so either, so we decided to give you an easy way to print out the story without all that icky implementation code (we're too familiar with that glossy eye look stakeholders get when you show them code).

Story printing is available from command line as a format flag as well as via the easyb ant task. For instance, below is an example of two stories-- one with two scenarios and the other containing three.

This example also shows what you see when a specification isn't filled out and is marked as pending.


33 specifications (including 2 pending) executed successfully


  Story: empty stack

    scenario null is pushed onto empty stack
      given an empty stack
      when null is pushed
      then an exception should be thrown
      then the stack should still be empty

    scenario pop is called on empty stack
      given an empty stack
      when pop is called
      then an exception should be thrown
      then the stack should still be empty

  Story: single value stack

    scenario pop is called on stack with one value
      given an empty stack with one pushed value
      when pop is called
      then that object should be returned
      then the stack should be empty

    scenario stack with one value is not empty
      given an empty stack with one pushed value
      then the stack should not be empty

    scenario peek is called
      given a stack containing an item
      when peek is called
      then it should provide the value of the most recent pushed value
      then the stack should not be empty
      then calling pop should also return the peeked value which is \
        the same as the original pushed value
      then the stack should  be empty
      then an example pending [PENDING]

  etc...

Easy story printing, eh?