Saturday, October 15, 2005

dave astel's behavior driven design with ruby

I read Dave Astel's A Pratical Guide to Extreme Programming some time back, and I just started reading Test-Driven Development. So, I'm excited to hear that he may start work on a new book about what he is calling Behavior Driven Design, an approach that extends the concept of unit testing to a higher level where you are thinking less about verification of code at the unit level and more about the specification of design at the behavior and context level.

Dave and company have begun an xUnit type framework around this idea. Low and behold, Steven Baker, Aslak Hellesoy, Gabriel Baumann, and Dave wrote rSpec in Ruby, available as a gem.

In his intro paper on BDD, Dave says:
"Thinking about unit testing leads us to divide tests in a way that reflects the structural arrangement of the code. For example, having text classes and production classes in a 1-1 relationship. That's not what we want... we want behavioural divisions.. we want to work at a level of granularity much smaller than that of the typical unit test. As I've said before when talking about TDD, we should be working with very small, focused pieces of behaviour... one small aspect of a single method."

He goes on to show an example of some specs for a Movie and MovieList class:

require 'spec' 
require 'movie'
require 'movie_list'

class EmptyMovieList < Spec::Context
def setup
@list = MovieList.new
end
def should_have_size_of_0
@list.size.should_equal 0
end
def should_not_include_star_wars
@list.should_not_include "Star Wars"
end
end

class OneMovieList < Spec::Context
def setup
@list = MovieList.new
star_wars = Movie.new "Star Wars"
@list.add star_wars
end
def should_have_size_of_1
@list.size.should_equal 1
end
def should_include_star_wars
@list.should_include "Star Wars"
end
# vc: I added this bit
def should_not_include_serenity
@list.should_not_include "Serenity"
end
end


So now with a specification for the behavior of the classes, you implement the system to pass the spec.

Here's what I came up with to implement the classes to test out rSpec:

class Movie
attr_accessor :title
def initialize(title)
@title = title
end
def to_s
@title
end
end

class MovieList
def initialize
@list = []
end
def size
@list.size
end
def add(movie)
@list << movie
end
def include?(title)
(@list.find {|movie| movie.title == title }) != nil
end
end


Now you run 'spec' from the command line. (I don't think they have a runner yet).
>> spec spec_movie_list.rb

.....

Finished in 0.01058 seconds

5 specifications, 5 expectations, 0 failures

Voila, the classes pass the specification!

You can find out more on Dave Astel's blog, the original post that started it all, and this podcast.

[UPDATE: Steven Baker is giving a workshop on Agile Rails Development at Canada on Rails this April. Looks like he will be talking about TDD vs. BDD and likely his RSpec testing framework. I'm having trouble deciding which conference I should attend this year. Vancouver is closer (and cheaper) than Chicago, but they haven't announced who the speakers are or what the sessions will be yet, so hard to say.]

0 Comments:

Post a Comment

<< Home