Fork me on GitHub

easyb stories

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.

Structure of a Story

Narratives

easyb supports the notion of narratives, which attempt to set the stage of a story. Narratives use a narrative clause followed by a series of descriptors that can either be written with underscores or not.

For example, the following narrative describes a story regarding currency management: .Groovy Example

narrative "regarding currency management", {
 as a "person who uses money"
 i want "to be able to add currencies together"
 so that "that I can become rich over time"
}

Scenarios

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)

Data

Scenarios can be supplied with examples. Adding a where clause to a scenario results in the scenario being executed multiple times — once for each row of data.

Given (a context)
When (something happens)
Then (something else happens)
Where (a source of structured data)

Variable Replacement

If variables are in context at the time your story is running (e.g. they are in a before, before_each or where clause), you can use them in the text of your story. Because of the way Groovy works, the $ symbol is not usable, and has been replaced with # (to be consistent with Spock). To forms are available:

Table 1. Variable Replacement
Format Type Description

"#number is given"

Simple

If a value for 'number' exists in the binding at the time (say 5) of execution, this will appear as "5 is given"

"#total should be #{val1 + val2}"

Closure

When a closure is embedded easyb creates a (reused) Groovy script which is passed the binding and can thus have any Groovy code in it. It is slower than the first option.

Fixtures

If you’d like to re-use a bit of logic throughout a story, you could use easyb’s before or before_each keywords to delineate a fixture like so: .Groovy Example

before "start selenium", {
 given "selenium is up and running", {
  selenium = new DefaultSelenium("localhost",
    4444, "*firefox", "http://acme.racing.net/greport")
  selenium.start()
 }
}

In the code above, an instance of Selenium is started once for the entire story — if you’d like to start Selenium for each scenario, then you’d use the before_each keyword.

Ideally, any before or before_each clauses should reside in the beginning of a story; what’s more, easyb supports post style fixtures via after and after_each — these clauses should reside at the bottom of story.

Shared behaviors

Somewhat similar to fixtures is easyb’s notion of shared behaviors — these are a bit more logical in that rather than creating a before-style clause, you construct a basic scenario and then refer to it later in other scenarios. In essence, this style of re-use is a bit more descriptive.

Shared behaviors use easyb’s shared_behavior and it_behaves_as clauses like so: .Groovy Example

shared_behavior "shared behaviors", {
  given "a string", {
    var = ""
  }

  when "the string is hello world", {
    var = "hello world"
  }
}

scenario "first scenario", {
  it_behaves_as "shared behaviors"

  then "the string should start with hello", {
    var.shouldStartWith "hello"
  }
}

scenario "second scenario", {
  it_behaves_as "shared behaviors"

  then "the string should end with world", {
    var.shouldEndWith "world"
  }
}

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.

Example 1: An easyb Story
import io.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?

For more examples and information on stories, see easyb’s Story examples section.