ATDD, Cucumber and Scala


Acceptance Test Driven Development (ATDD) is a practice in which the whole team collaboratively discusses acceptance criteria, with examples, and then distills them into a set of concrete acceptance tests before development begins. If you notice the keywords here then they are

whole team discussion
acceptance criteria
with examples
concrete acceptance tests
before development begins

Hence, just like we do TDD for development, ATDD is an important practice to get your test cases in place before beginning the development of a user story. These acceptance tests are then shown to the stakeholders and the functionality is verified. Changes if any, are made and the development begins. But wait! acceptance test cases, shown to the stakeholders? Which world do we live in? Do they understand the technical mumbo-jumbo? Isn’t the idea of acceptance tests to provide a clear feedback that the story is done?

Well, as you guessed you are right in most scenarios. Precisely for that reason, we need to separate out what the technical crap from what the stakeholders understand. Enter Cucumber.

Cucumber separates out the features which the stakeholders understand from the mapping code which binds these features to the corresponding acceptance test code which tests the software functionality. It would become clear from the diagram below

cucumber

As you would notice, the stakeholders would look at the features and comment whether the features have the output that they are expecting. The mapping code would responsible for running the features and verifying that the output matches the expectation.

A typical feature file would look like this

Feature: Multiplication 
  In order to avoid making mistakes
  As an accountant
  I want to multiply numbers

  Scenario: Multiply two variables
    Given a variable x with value 3
    And a variable y with value 4
    When I multiply x * y
    Then I get 12

So we define a feature called multiplication. For making the intent understandable we define the user story in the format “In order to As a I would like to “. Every feature would have multiple scenarios which would include happy path and alternate paths.

Feature Scenario and Steps

For all such scenarios we would specify the
1) Preconditions
2) Input
3) Output

The corresponding mapping in the feature file scenario would be
Precondition == Given, And
Input == When
Output==Then

As you would notice, any file like this is easily understandable by the stakeholders. Hence, they view the file and validate that our understanding is correct. Now we need to do the interesting part of adding the mapping so that we can make this feature file “executable”

We need to include the following dependencies

resolvers += "Templemore Repository" at "http://templemore.co.uk/repo"

addSbtPlugin("templemore" % "sbt-cucumber-plugin" % "0.7.1")

Once we have this plugin sorted out, we have to include a corresponding Scala file which would work with the values defined in the feature file. In our scenario, the Scala file looks like this

import cucumber.api.scala.{ScalaDsl, EN}
import org.scalatest.matchers.ShouldMatchers
import scala.collection.mutable.{Map => MutableMap}

class MultiplicationSteps extends ScalaDsl with EN with ShouldMatchers {

  val vars = MutableMap[String,Int]()
  var result = 0

  Given("""^a variable ([a-z]+) with value (\d+)$"""){ (varName:String, value:Int) =>
    vars += varName -> value
  }
  When("""^I multiply ([a-z]+) \* ([a-z]+)$"""){ (var1:String, var2:String) =>
    result = vars(var1) * vars(var2)
  }
  Then("""^I get (\d+)$"""){ (expectedResult:Int) =>
    assert(result === expectedResult)
  }
}

As you would notice, we are defining a regular expression match, just like Cucumber needs them. Hence Given(“””^a variable ([a-z]+) with value (\d+)$”””) would match “Given a variable x with value 3″. The variable x is now bound to varName and the value 3 is bound to value. In our code we just store it in a mutable map for now.

“And a variable y with value 4″ is also matched with the same Given regular expression and the value of y is stored as 4.

When(“””^I multiply ([a-z]+) \* ([a-z]+)$”””) matches “When I multiply x * y” and as a result of that we end up getting the values from our map and multiplying them. Likewise for Then to match the result.

When this feature file is now executed with

$ sbt cucumber

we get an output similar to
cucumber run output

A working example which was forked from https://bitbucket.org/jordipradel/cucumber-scala-example and made to work with SBT 0.12.1 and Scala 2.10 can be found here.

Thus, cucumber provides an efficient way of separating out the feature files which are well understood by the stakeholders and the mapping Scala files where we can play :) It provides an excellent medium to communicate in the ubiquitous language which is understood by the business. In another post, we would look at how to achieve something similar with our own ScalaTest framework. Till then.

About these ads

About Vikas Hazrati

Vikas is the CTO @ Knoldus which is a group of software industry veterans who have joined hands to add value to the art of software development. We do niche product and project development on Scala and Java. We consult and coach on effective software development and agile practices. With our focus on software craftsmanship you can be assured of a good quality at the right price. To know more, send a mail to info@knoldus.com or visit www.knoldus.com
This entry was posted in Scala and tagged , , , , . Bookmark the permalink.

3 Responses to ATDD, Cucumber and Scala

  1. Pingback: ATDD, ScalaTest and Scala | Knoldus

  2. Pingback: ATDD, ScalaTest, Cucumber and respecting DRY | Knoldus

  3. Pingback: Cucumber in Scala | Elegant Coding

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