Sunday, June 23, 2013

Behavior Driven Development (BDD)

Behavior Driven Development (BDD)
http://en.wikipedia.org/wiki/Behavior-driven_development

When I joined my team, BDD was the buzz word. Initially it didn't make sense to me since most of the time I ended up writing steps to test what I'm going to develop. Aren't unit tests enough to test the functionality of classes I write ?

Let's say I'm going to implement the world's best calculator service 'foobar' which will talk to the super computer 'Param Padma' to do calculations. Where should I start ?

Well, I'll think about my design, draw a bunch of UML diagrams in whiteboard, write my interface, write some unit tests, implement the interface, make the unit tests pass and hand it over to QA. Now it's someone else's headache. Then I release the service to public and oops something is broken. I fix it, hand it over to QA, fix works, release the patch. Oooops.. it's not even adding two numbers anymore. Customers get pissed off and eventually your service will go down the drain. Trust me, most developers would have gone through this vicious and error prone cycle. As a developer I need some confidence to make code changes, fix bugs, refactor, optimize. I need a safety net around my code. Writing functional tests is one way to placate the above scenario. The idea of BDD is to do the development backwards starting from writing the functional tests. 

To start with, we have to identify different features of our service and then identify independent testable scenarios in each feature. A feature file might look something similar to this for our awesome 'foobar',
 
Feature: Perform arithmatic operations

As a client of foobar
I should be able to perform calculations on numbers
So that I can use the results to do something awesome

Scenario: Add two numbers
Given I have two numbers 1 and 2
When I ask foobar to add the numbers
Then I should get back 3

Scenario: Divide two numbers
When I ask foobar to divide 1 by 0
Then I should get an error saying "divide by zero"
....
....

If somebody wants to know about what our service does, feature files will tell them a story. Essentially we enumerate the customer facing functionality of our service as scenarios. Next, we associate step definitions for each of the above steps using one of the BDD frameworks. I've tried cucumber. It is simple and effective. (It is also one of the examples of how not to write software, but that's a different story in a separate blog)
"Given I have two numbers" 
public void I_have_two_numbers(int a, int b) 
{ 
  setA(a); 
  setB(b); 
}
 
"When I ask foo bar to add the numbers" 
public void I_ask_foo_bar_to_add_the_numbers() 
{
  FooBar foobar = MyAwesomeServiceInterface.getFooBarClient(); 
  // This step will actually make calls to 'param padma' and return the sum unlike a mock service.
  setSum(foobar.add(getA(), getB()));
}
 
"Then I should get back"
public void I_should_get_back(int expectedSum) 
{
  assertEquals(expectedSum, getSum());
} 

When we run the test suite, for each step in feature file, the corresponding step definition will be executed. So what have we gained out of all these?

·         We have clearly defined the functionality of our service, so there is no room for scope creep during implementation.
·         Before even writing the service we'd know how painful/easy it is going to be for the users to interact with our service.
·         We are implementing what we test and not testing what we've implemented.
·         The success criteria are crisp. Just make the steps pass and our service is ready.
·         The quality of code is better since it is easily maintainable. 

I've been practicing this for a while and it makes development so easy. A close metaphor would be 'swimming with a life jacket on'. Ciao in another post.

~Surya

No comments:

Post a Comment