August 2007

Is BDD TDD done right?

Every once in awhile, in this Age of Aquarius, when I talk with people about Behavior Driven Development (or BDD) they mention that BDD sounds a lot like TDD done right, man. By that, they mean that like TDD, BDD enables you to think in terms of behavior (or tests/validation in TDD speak) up front (or first). The beauty of thinking about these constructs first is that it, in essence, drives development in a much more fluid manner that permits refactoring and collaboration with copasetic domain experts. This style of coding also builds in confidence up front.

Because it’s my bag, I happen to agree with this notion (that BDD is TDD done right) but I find that BDD makes it a whole lot easier because it drops the word “test” in favor of “should”. And, as I’ve found, should rolls off the tongue quite naturally, man. Take the simple example of a queue data structure. Imagine someone has asked you to describe one– maybe you’d say something like this (note that I even left out the hip filler words in your favor, baby):

A queue is a first in first out data structure. It accepts items via an enqueue method and when dequeue is called, the oldest item (the item who was enqueued before everything else) in the queue should be returned. If dequeue is called on an empty queue, an exception should be thrown; plus, enqueue shouldn’t accept null as a value.

Notice how the phrase “should” popped up here and there quite naturally. Via this description, you can easily start to see BDD in action. For example, given the description of the queue, you can start to define behavior from the sentences like “enqueue shouldn’t accept null as a value.” There are a few different BDD frameworks for you to choose from on practically every platform– one of the more innovative ones is RSpec for Ruby. This particular framework has a particularly hip DSL for defining behavior– watch:

I’ll start with an easy behavior to define– an exception should be generated if someone attempts to enqueue null (or nil in hip Ruby terms). RSpec may look strange at first, but once you’re used to it, it looks quite natural (and elegant). First, rather than declaring a class, you use the describe phrase. You can also use a special method named before (the :each means for each specification) that acts like a normal fixture in xUnit terms.

require 'queue'

describe Queue do

  before(:each) do
    @queue = Queue.new
  end

end

Next, you can define behavior via the tripping it phrase.

it "should raise an error if nil is enqueued" do
  lambda { @queue.enqueue(nil) }.should raise_error(RuntimeError)
end 

Note the lambda phrase– it’s a pretty slick mechanism much like a closure. You can imagine that RSpec keeps on truckin’ and takes the phrase @queue.enqueue(nil) and executes it within a try/catch (or rescue claus) checking what kind of error was raised. Of course, running this behavior at this point won’t work– the Queue class doesn’t exist! All I have to do is implement the desired behavior– raise an error if nil is enqueued.

class Queue

  def enqueue(item)
    if item == nil then raise RuntimeError.new("can not enqueue nil")
    else
    end
  end
end

Now I can run it:

aglover$ spec queue_spec.rb
.
Finished in 0.005292 seconds
1 example, 0 failures

The next behavior regards dequeue when nothing has been enqueued.

it "should raise an error if there isn't anything to dequeue and dequeue is called" do
  lambda {@queue.dequeue}.should raise_error(RuntimeError)
end

Implementing this behavior in the Queue class is pretty easy, man:

def dequeue
  raise RuntimeError.new("nothing to dequeue")
end

The next behavior gets to the real meat of a queue– that is, when you enqueue an item (and it is the only item in a queue) when you call dequeue, you should get that item back.

it "should return item enqueued" do
  @queue.enqueue("test")
  @queue.dequeue.should == "test"
end

By coding this behavior, it becomes evident that the Queue needs some backing collection to actually hold items– otherwise the meat of a queue isn’t there. Isn’t cool, by the way, that RSpec (in concert with Ruby’s MOP implementation) allows me to call should on any old object?

def initialize
  @items = []
end

With an internal array (defined in the constructor of the Queue class) now holding the items of the Queue, I can now code the enqueue method to first check for nil– if the item isn’t nil then add it to the array.

def enqueue(item)
 if item == nil then raise RuntimeError.new("can not enqueue nil")
 else @items << item
 end
end

If I run my hip behavior class, it’ll still fail as the behavior method enqueues and then dequeues an item; hence, I need to code dequeue, which I can code per the spec: “when dequeue is called, the oldest item (the item who was enqueued before everything else) in the queue should be returned.”

def dequeue
 if @items.empty? then raise RuntimeError.new("nothing to dequeue")
 else return @items.delete_at(0)
 end
end

Running my behavior now yields a pass. I’d like to add a few more behavior methods just to verify things are kosher though.

it "should dequeue first item added" do
 [1,2,3,4].each{  | val | @queue.enqueue(val)}
 @queue.dequeue.should == 1
end 

The behavior method above adds a few items and ensures that the first one to be dequeued is the oldest that was added. Now that that works, I want one more behavior that ensures that things are dequeued in reverse order– as you can see below, it isn’t too hard to do in Ruby, man!

it "should dequeue items in reverse order" do
 values = [1,2,3,4]
 values.each{  | val | @queue.enqueue(val)}
 values.each{ | val |  @queue.dequeue.should == val }
end 

So is BDD TDD done right? In essence, yes, but hopefully you’ve seen that BDD’s should construct makes the effort of defining behaviors up front quite easy. In fact, because it’s my bag, I think BDD is easier to adopt than strict TDD dogma. Dig it, man?

The weekly bag– August 24

The weekly bag is back, baby!

Take note of this quote

I had the pleasure of meeting Gerard Meszaros, the author of the ever so hip “XUnit Test Patterns” book (which is in the Martin Fowler signature seriesThe CI Book is also a member, man) recently at a dinner hosted by Stelligent (my copasetic employer) and he said what I think is the quote of the year (so take note, man).

Because it’s his bag, in a conversation with roughly 30 people (over a fine meal consisting of fillet mignon among other tasty victuals) regarding Agile processes and the discipline required to maintain such agility, Gerard used the analogy that it is unacceptable for a doctor to go into an operating room without having scrubbed in (i.e. washing his/her hands); consequently, it should be impermissible for a developer to write code without having written some tests (ideally unit tests) for said code.

In fact, Darryl Taft of eWeek (who was also in attendance) captured Gerard’s words succinctly in his article “Agile Brings Professionalism to Software Development“:

“Not scrubbing before you go into surgery is a no-no, and not writing unit tests is not acceptable.”

Check out Darryl’s article and the next time you let it all hang out and fail to write a test for the nasty mess of code, you had better hope if you ever are cut open that the cutter washed their hands in advance, man!