ScalaTest 104: Adding Given/When/Then behavior to ScalaTest BDD tests

Scala Problem: You want to make your ScalaTest unit tests more BDD-like by adding “Given/When/Then” behavior to them.

Solution

Mix the GivenWhenThen trait into your FunSpec BDD test, then add the Given/When/Then conditions, as shown in the following code:

package com.acme.pizza

import org.scalatest.FunSpec
import org.scalatest.BeforeAndAfter
import org.scalatest.GivenWhenThen

class PizzaSpec extends FunSpec with GivenWhenThen {

  var pizza: Pizza = _

  describe("A Pizza") {

    it ("should allow the addition of toppings") {
      Given("a new pizza")
      pizza = new Pizza

      When("a topping is added")
      pizza.addTopping(Topping("green olives"))

      Then("the topping count should be incremented")
      expectResult(1) {
        pizza.getToppings.size
      }

      And("the topping should be what was added")
      val t = pizza.getToppings(0)
      assert(t === new Topping("green olives"))
    }
  }

}

Assuming that you have the Pizza and Topping classes installed as described in Writing TDD Tests with ScalaTest, this class prints the following test output, which provides more detail to anyone reviewing the output:

[info] Compiling 1 Scala source to 
/Users/Al/Projects/Scala/Tests/ScalaTest1/target/scala-2.10.0/test-classes...
[info] PizzaSpec:
[info] A Pizza 
[info] - should allow the addition of toppings
[info]   + Given a new pizza 
[info]   + When a topping is added 
[info]   + Then the topping count should be incremented 
[info]   + And the topping should be what was added 
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0

Discussion

Where Writing a First BDD Test with ScalaTest got you started down the road of the BDD-style of testing, adding the GivenWhenThen trait gives you the additional features necessary to more fully implement the BDD style.

Dan North, the creator of the BDD style of testing, describes the Given/When/Then approach on his website. He shows that the basic pattern looks like this:

  • Given some initial context (the givens),
  • When an event occurs,
  • Then ensure some outcomes.

A simple example of this might look like this:

  • Given a new pizza
  • When a topping is added
  • Then the pizza should have one topping

A more complicated example might look like this:

  • Given a new pizza
  • When new toppings are added
  • And the size is set
  • And the crust type is set
  • Then the pizza should have all of those toppings
  • And the crust size should be correct
  • And the crust type should be correct
  • And the price of the pizza should be X

Adding more tests

As you can see from the output, the Given method prints “Given” before your string; When prints “When” before your string; and so on with Then and And.

As you add more BDD-style tests to your class:

it("Should start with no toppings") {
  Given("a new pizza")
  pizza = new Pizza
  Then("the topping count should be zero")
  assert(pizza.getToppings.size == 0)
}

it("Should allow removal of toppings") {
  Given("a new pizza with one topping")
  pizza = new Pizza
  pizza.addTopping(Topping("green olives"))

  When("the topping is removed")
  pizza.removeTopping(Topping("green olives"))

  Then("the topping count should be zero")
  expectResult(0) {
    pizza.getToppings.size
  }
}

you end up with test results that read like a software specification:

[info] Compiling 1 Scala source to /Users/Al/Projects/ScalaTest1/target/scala-2.10.0/test-classes...
[info] PizzaSpec:
[info] A Pizza 
[info] - Should start with no toppings
[info]   + Given a new pizza 
[info]   + Then the topping count should be zero 
[info] - Should allow the addition of toppings
[info]   + Given a new pizza 
[info]   + When a topping is added 
[info]   + Then the topping count should be incremented 
[info]   + And the topping should be what was added 
[info] - Should allow removal of toppings
[info]   + Given a new pizza with one topping 
[info]   + When the topping is removed 
[info]   + Then the topping count should be zero 
[info] Passed: : Total 3, Failed 0, Errors 0, Passed 3, Skipped 0

See Also

  • A description of Behavior-Driven Development on Wikipedia: http://en.wikipedia.org/wiki/Behavior-driven_development
  • Dan North’s original “Introducing BDD” article: http://dannorth.net/introducing-bdd/
  • ScalaTest's given/when/then documentation: http://www.scalatest.org/getting_started_with_feature_spec

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote, and was published by O’Reilly in late 2013:

You can find the Scala Cookbook at these locations:

I hope it has been helpful. All the best, Al.