[rspec-users] How to write the very first example?
dchelimsky at gmail.com
Sun Sep 30 10:55:21 EDT 2007
On 9/30/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote:
> Thanks for clearing things up Pat!
> I'll give the story stuff I try, I haven't looked at it yet.
> Does this actually mean I need to start describing some stories, then start
> with writing the examples/code for the first story by using mock objects for
> every layer?
Here's how I do this. I start with a set of stories and scenarios
expressed only in text (no code in the Given/When/Then steps). I pick
a scenario to start with and fill in the code, writing the code I wish
I could write as I go. This helps me to discover the outermost objects
and their APIs.
Next, I pick one of the objects from the story and start driving it
out with examples. The first examples will often overlap a bit with
the stories and this is OK. Even expected.
For anything that is needed by the object I'm working on at any given
moment, if the code already exists to support it and using it is not
expensive (in terms of required setup or processing cycles) I'll use
it. If the code is not there yet, or it is expensive to use, I'll
introduce a mock.
> Do I eventually need to replace all the mocks by real objects?
You don't ever *need* to replace the mocks with the real objects, but
you certainly can. The reason you don't need to is that the
Stories/Scenarios will fail when there is a mismatch between a mocked
object and the real object.
As to whether you *should* replace them, there are several schools of
thought that generally resolve around responsibility and behaviour.
For example, if we call foo.validate and that, in turn, calls
validator.validate(self), where is the responsibility for validation?
Some say it is foo's responsibility, some say it belongs to the
validator. That debate is out of scope for this discussion, but there
are plenty of other discussions on this list that you can mine for
ideas about this.
Another factor that comes into play is the level of complexity of the
setup. If you have to mock 3 layers deep, then maybe it's better to
use the real object. Of course, if you have to mock 3 layers deep,
there might be a design problem.
> And is it bad to do partially stubbing on objects, or does this indicate an
> object should provide more information about its state?
Well, it's always better if you can avoid revealing information about
state. Tell, Don't Ask. But sometimes it is a necessary (or at least
very useful) evil. And even when you're just telling (i.e. no
state-exposure necessary) the same question might come up.
It really depends on context. I think it's reasonable to ask that
question whenever you're using partial mocking/stubbing. Sometimes the
answer is going to be that the object should respond to some new
message, sometimes not.
> For instance, take a look at this pastie http://pastie.caboo.se/102174, is
> this a good way to write an example for a behaviour or am I taking a wrong
In the text above the code under development, it says "Read the
repositories from a file, notify the user for updates in all
repositories," but the example says "should call notify_if_updates on
every repository." This is pretty interesting, because the example
uses an implementation-specific description, whereas the comment
describes behaviour at a higher, more abstract level. So I'd start by
changing the example to read "should notify the user if there is an
update in any repository", with another example (likely several
others) that reads "should not notify the user if there are no updates
to any repository".
Of course, this starts me thinking that notifying the user is really
not Base's responsibility, and that notify_if_updates should accept a
notifier, listener, callback, etc. at which point the example is
"should provide a callback to each repository to use if the repository
So, the feeling I get from looking at this particular example/code is
that it started from the code, not the example. I could be wrong -
that's just how it feels to me.
> I feel the need for some small, simple, clean example programs, to take a
> look through.
> Maybe, I just need to put my current pet project online and let people shoot
> at it.
That would certainly be a powerful learning experience for you if you
have the stomach to absorb criticism that is only sometimes
constructive. It would probably be so for all of us.
One thing to keep in mind if you do this experiment is that BDD is a
process, and you'll be showing and getting feedback on a result. There
is something to be learned from the result, but the real money is in
the process, so you'll have to do some extrapolating from the
criticism and apply it back to the process - unless of course you want
to turn it into a complete tutorial with step by step explanations of
every decision you made along the way. I can tell you from experience
that it is a LOT of work ;)
> - Matthijs
> On 9/30/07, Pat Maddox <pergesu at gmail.com> wrote:
> > On 9/29/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote:
> > > Many posts on this list are about using RSpec with Rails and that's the
> > > I'm also using RSpec all the time.
> > > Unfortunately there isn't that much info about using RSpec for
> > > 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
> > > for a fresh standalone Ruby project. I haven't really got a clue where
> > > start, how to call the first example and how to describe it.
> > Begin at the beginning :P
> > 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" 
> > 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 North's article about introducing rbehave  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
> > > 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
> > > 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
> > 1. 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.
> > 2. 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
> >  http://evang.eli.st/blog/2006/12/18/design-deep-not-wide
> >  http://dannorth.net/2007/06/introducing-rbehave
> > _______________________________________________
> > rspec-users mailing list
> > rspec-users at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-users
> rspec-users mailing list
> rspec-users at rubyforge.org
More information about the rspec-users