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
enqueuemethod and whendequeueis called, the oldest item (the item who was enqueued before everything else) in the queue should be returned. Ifdequeueis called on an empty queue, an exception should be thrown; plus,enqueueshouldn’t acceptnullas 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?
Tuesday 28 Aug 2007 | Andy | Developer Testing, Ruby
[…] Lastly, my apologies to those that were hip enough to comment on my recent post “Is BDD TDD done right?“– apparently my hosting provider’s database went down and they had to restore it with a backup that didn’t include that post nor its comments. Luckily, I had a copasetic copy of the post, however, I didn’t have the comments. Thanks again folks– your feedback and links were excellent. […]
[…] BDD, TDD, and the other Double D’s Behavior Driven Development (BDD) has been a pretty big topic in some of the email groups I lurk in. I’m seeing BDD cast as a whole new paradigm of development, where as I see BDD as an evolution of TDD with a better syntax and mechanics for expressing the desired functionality with tests/specifications. That’s more than enough advantages to jump into BDD and plenty to be excited about, but not enough to designate BDD as a whole new paradigm. Andy Glover described BDD as TDD Done Right and I concur. […]
[…] Stacking it up with BDD, baby As I’ve mentioned before, Test-driven development (or TDD, man) is a copasetic idea in practice, but some jive turkeys just can’t get over the conceptual leap associated with that word test. Check out this month’s “In pursuit of code quality” article, entitled “Adventures in behavior-driven development” to see, what’s arguably, a more natural way to integrate the momentum of TDD into your programming practice. Get started with behavior-driven development (aka BDD) (via JBehave, baby) and see for yourself what happens when you focus on program behaviors, rather than outcomes. […]
[…] Go easy with specifying behavior, man RSpec’s DSL is so hip that I recently found myself wanting that same simple expressiveness in Java (by the way, there’s nothing stopping someone from using RSpec with Java via JRuby)– in fact, what I want is a simple framework that facilitates letting non developers specify behavior. For instance, taking a terribly simple (yet hip) example, imagine (again) a queue data structure. If you were to break it down into a simple narrative, you may end up with something like this: A queue’s basic behavior can be descirbed as: it: […]
[…] I’ll be speaking about BDD, Groovy, and a Martin Fowler inspired subject regarding the future of build languages. My BDD talk will obviously focus on how BDD can drive development more effectively than TDD and I’ll demonstrate some JBehave, RSpec, and a Groovy inspired RSpec knock-off. My Groovy session is a veritable crash course on using Groovy quickly– 101 style, baby. Lastly, the build languages openspaces session is an open discussion regarding Ant style (i.e. XML driven platforms like NAnt and MSBuild) build platforms versus more expressive platforms like Rake, Raven, and Gant, for example. […]
[…] BDD in Java just got easier Behavior driven development has been my bag lately; in particular, I have found the subtle shift in thinking in terms of behavior easier than that of tests. By thinking about behavior (which is, in essence, the specification of a hip object, for example), it becomes easier to validate things early-– in fact, when thinking in terms of a specification, it becomes copasetically easy to write things upfront. What’s more, one exceptional BDD framework, RSpec, has a remarkably hip DSL that reads like plain English, making the whole process easy (and fun). […]
[…] RSpec, a Ruby on Rails test extension, has inpired some Java devotees to try and roll out similar framework in Java. The paradigm is coined BDD(Behavior Driven Development, here’s an introduction / statement of independence), and the framework, including some enlightening documentation, can be found here. […]