On 9/29/07, Matthijs L. [email protected] wrote:
Many posts on this list are about using RSpec with Rails and that’s the way
I’m also using RSpec all the time.
Unfortunately there isn’t that much info about using RSpec for standalone
Ruby projects.
I don’t think that matters much, the principles are the same. You
write stories for features, and write specs to drive object
implementation. In fact I would say that Rails presents some unique
challenges for BDDing, and that a “pure” ruby project is easier!
I must admit I’m really having a hard time writing the very first example(s)
for a fresh standalone Ruby project. I haven’t really got a clue where to
start, how to call the first example and how to describe it.
Begin at the beginning 
There are a couple approaches. First thing I would do is write a
story for one feature you want in the system. Having that story means
that you stay focused on one particular task and building the
infrastructure that will be used. I actually wrote a blog post a
while back on what I call “design deep, not wide” [1]
On a simpler level, stories represent real progress. When you’re done
with a story you should have actual value, and that is fulfilling and
motivating.
Also, you can start with smaller stories and build out from there. In
Dan N.'s article about introducing rbehave [2] he works with simple
objects instead of a full application stack like you might in Rails.
When I first read it, I thought a standard spec might be more
appropriate. Once it hit me though (which was a couple months later),
I fell in love with that approach.
To give you an idea, here’s the starting code:
Story “transfer to cash account”,
%(As a savings account holder
I want to transfer money from my savings account
So that I can get cash easily from an ATM) do
Scenario “savings account is in credit” do
Given “my savings account balance is”, 100
Given “my cash account balance is”, 10
When “I transfer”, 20
Then “my savings account balance should be”, 80
Then “my cash account balance should be”, 30
end
Scenario “savings account is overdrawn” do
Given “my savings account balance is”, -20
Given “my cash account balance is”, 10
When “I transfer”, 20
Then “my savings account balance should be”, -20
Then “my cash account balance should be”, 10
end
end
Eventually he sticks objects in there as he implements them, but at
least at the very beginning there’s no code to speak of. It’s just a
user story. The beauty of it is that all you’re doing is specifying
acceptance criteria - what it means to be “done.” One scary part of
doing lower level specs is on some level you’re designing code without
any real sense of direction. You might not necessarily know what
objects you need. While specs are excellent for discovering the
behavior of objects, as far as what operations they perform and
interactions they have, they don’t do much to help with the desired
behavior of the system.
So, basically, writing stories forces you to think about what you want
to achieve, and gives you a clear way to measure progress. You know
where you want to end, and you know all the steps it takes to get
there, and that gives you the knowledge of where to start.
I want to use the outside-in approach, but that suggests the first example
you write should specify the workings of the whole project, right?
I alway catch myself focusing on dependancies and start from the inside
instead of the outside. (if I implement this first, I can use it as a
building brick for that feature, and if that feature is implemented I can
work on that other feature.)
This is where mock objects yield their greatest benefits. A lot of
people think mock objects are good only for isolating expensive
resources, but they’re fantastic in allowing you to design well in
chunks. For example, something as simple as:
customer.place_order some_item, 12
Will require that I have a customer class, a place_order method, an
item class, and probably an order class somewhere. I’m adding a
little feature, and all of a sudden I have to implement all these
classes, at least in bits, and because I’m only handling a little bit
of the behavior I don’t have any idea how they’re going to be used in
other parts of the system. It’s scary because there’s more pressure
to get it right the first time.
mocks, otoh, allow you to defer all of that until later. When working
on a feature, I can concern myself only with that feature and not
worry about all the plumbing that it may need. A couple things happen
there
- I tend to end up with a clean, layered architecture. This happens
because I’m only working on one layer at a time. When I’m bouncing
back and forth between layers, I have to be extra mindful of what I’m
dealing with, otherwise stuff that should be in one layer creeps into
another and now I’ve got a muddled, difficult to understand design.
- My life is easier! With mocks, I can isolate my thinking to a
certain level or chunk of the code. Instead of pushing and popping
all kinds of stuff on my mental stack, I limit the number of little
things I need to think about at one time. I wasn’t blessed with
unlimited brain space, so that’s a huge win for me. It also creates
extra room to think about what I’m doing at a higher level and keep
everything in perspective.
It’s interesting, because your questions really boil down to being
overwhelmed with what you have to do. It’s a feeling I know all too
well. Fortunately RSpec provides two tools that do a fantastic job in
easing the uncertainty. First you have user stories which help give
you direction in the project. You know what you want to get done,
have a good measure of progress as you implement it, and finally have
a clear understanding of when you’ve completed it. On a lower level,
mock objects help keep your thinking focused instead of running off in
all different directions writing the all the infrastructure that it
may take to write one line of code. You become less likely to code
yourself into a corner, and you keep your mental stack in check.
I hope that was helpful. I completely understand sitting at the
keyboard wondering just what the hell I should be doing. I’ve found
that RSpec helps me out a great deal both in terms of capturing
desired business outcomes and in implementing the code to achieve
them. It can take a while to really get it, but you may come to find
that once you do you’re hooked.
Pat
[1] eli.st
[2] http://dannorth.net/2007/06/introducing-rbehave