This article was sparked by a some conversations and discussions
at RubyConf 2005.
Test VS Behavior
It seems fashionable these days to say that Test Driven
Development is not about testing at all, but rather about
(fill in the blank), where the blank can be filled with
“design”, “behavior” or “specification”. At RubyConf this year, one
of the “informal” discussion sessions around the pool area drew a
large crowd of people to discuss this very topic.
The RSpec ruby library (from Steven Baker, Dave Astels and Aslak
Hellesoy) is a replacement for Test::Unit. Its main focus is to
change the terminology surrounding the whole TDD approach to software
development. I think this is key … it is not changing anything
fundamental about the processes, it is focused upon the words we use
in describing the process. But don’t be fooled into thinking this is
a matter of semantics only, for the very words we use to describe
something shapes our thought processes about the thing we are
describing.
BDD, or Behavior Driven Development, is an attempt to improve TDD
(Test Drive Development) by emphasizing the behavior specification
nature of traditional TDD. By freeing TDD from its test bound
terminology, we avoid some of the preconceptions (e.g. “Tests? Yuck!”)
that developers bring to the table when discussing TDD.
So What’s Different
So, what’s the real different between RSpec and Test::Unit? Compare
these two code snippets. First the “test” version:
class TestEmptyMovieList < Test::Unit::TestCase
def setup
@list = MovieList.new
end
def test_size_is_zero
assert_equal 0, @list.size
end
end
And now the specification version:
class EmptyMovieList < Spec::Context
def setup
@list = MovieList.new
end
def should_have_size_of_0
@list.size.should_equal 0
end
end
Note:This is from RSpec version 0.2.0 available as a gem
from RubyForge. The RSpec guys are currently thinking about using
domain specific language for specification. So expect RSpec to change
in the future.
We can see that the structure between the tests and the specifications
is very similar. Actually, more than similar, they are virtually
identical. We just use Context instead of TestCase, use methods
with any name rather than those that start with test_, and use
object based assertions rather than specific assert methods.
The result is something that reads rather naturally in ruby-accented
English. But the functionally is essentially that of Test::Unit, just
in different clothing.
Just Semantics!
I hear you saying “But it’s just semantics!” Of course it is. But
leave out the word “just”. When conveying meaning, semantics is
everything. And one of the important features of Agile developement
is to convey the meaning of the code, in the code itself.
Semantics are important!
Is it worth it?
Ok, semantics are important. But is it worth converting all our unit
tests into specifications?
Maybe.
I do find the terminology attractive. But I have a large investment
in Test::Unit style tests at the moment. And RSpec is still a bit
rough around the edges (for example, the error reporting is not quite
as mature as Test::Unit’s). And RSpec is going through some major
changes at the moment (I mentioned the specification DSL they are
playing with).
What would I like to see? One area of specification that current TDD
practices tend to be weak in is the specification of preconditions.
Preconditions define under what circumstances it is valid to call a
method. For example, it may be invalid to call a square root function
with a negative argument. Looking at a list of tests (umm … specs),
I can’t be sure if negative inputs are not allowed, or if the spec
writer just forgot the cover that case.
I’m not ready to switch over to RSpec yet, but it certainly is moving
in interesting directions.
What I didn’t talk about
Those of you who were present at the poolside conversation at RubyConf
may wonder why I didn’t mention mock objects, since mock objects were
a major part of that debate. I see the Behavior VS Test debate to be
completely orthogonal to the Mock VS not-Mock discussion. I’ll pick
up the mock object debate in another posting, so don’t worry.