On Feb 25, 2008, at 8:30 AM, David C. wrote:
both approaches? How have they worked out for you?
I won’t wait for your answer :). But I am curious about other people’s
experiences with this.
I can tell you this from my own experience - I tend to use shared
groups for this for a couple of reasons. One, I like to see the specs
for each object.
I thought I’d share my experiences with the group. Please recall I’m
new at BDD/TDD so I may get some of the terminology wrong or whatever.
So I have a class that, by itself, doesn’t do anything. Concrete
subclasses are necessary to flesh out a few characteristics before the
parent class code can perform its magic. This is an abstract class
which I’m told isn’t the Ruby Way, so I’m looking at turning it into a
module (a topic for another message).
Originally, I was curious how to refactor my classes (and tests). I
decided to write a second concrete subclass to see what kind of
problems I might run into. I figured any problem I encountered was
just more information for me to figure out the correct direction. The
second subclass started out normally enough. I spec’d some behavior
unique to that subclass. So far, so good. Then it occurred to me that
I had no idea if the parent class was really being exercised by my new
tests; turns out it wasn’t being exercised.
To resolve this I started adding some tests to make sure I covered the
original behavior of the parent class. Now I had code duplication. The
parent class tests and my first subclass were duping some of the
same behavior. Looking into the examples directory I saw the concept
of #shared_examples_for.
I refactored my tests using shared examples. Most of these went into
the parent class (perhaps soon to be a module). All the tests in my
subclasses then focused exclusively on the behavior unique to that
specific class while the describe blocks called #it_should_behave_like
for shared behaviors. This DRY’ed the code up considerably.
An added benefit was some test breakage I ran across while refactoring
the tests. My second subclass had some rather tight coupling to the
tests, so when I made it shared the subclass test broke. It forced me
to rethink some of the test and class design to loosen the coupling.
Ultimately it led to a better class api.
So, that’s my rambling summary. Kudos to you if you read this far.
My next goal is to DRY up some of my ‘before (:each)’ blocks. I
continually do the same setup operations across #describe blocks (@buf
= Buf.new; @msg = blah, etc). It looks like I may want to define
subclasses of a parent Spec::ExampleGroup so the subclasses can
inherit some of the #before setup. I’d love to hear experiences from
others on this technique.
Lastly, I thought I’d say a word on the resulting class code. This BDD
project was a learning experience. I rewrote a set of classes that I
had originally written the old-fashioned way; puzzle through the logic
in my head, write the code, and then debug the crap out of it until it
worked. The original classes are rather short (LOC) with only a few
methods (3 or 4). The classes I wrote via BDD are longer, maybe by 40%
in terms of LOC. Plus, I now have around 10 methods none of which
exceeds 5 lines of “real” code. It’s more readable, more logical, and
far easier to subclass. I’m now a believer.
YMMV.
cr