[rspec-users] how to spec a recursive method that creates db records?

Stephen Eley sfeley at gmail.com
Mon Jul 20 23:45:54 EDT 2009

On Mon, Jul 20, 2009 at 8:33 PM, Barun Singh<barunio at gmail.com> wrote:
> I want to find a way to write a spec for this method that does both of these
> things:
> (1)  stub out the do_something method (that method has its own specs)
> (2)  not stub out the logic in the else statement, (there is some complex
> logic in there involving sql queries on multiple tables and i explicitly
> want to make it touch the database so that I can examine the state of the
> database after the method is run in my spec.  a lot of complex stubs would
> be required to do this while also having the spec that is actually useful)

Okay, first off -- I think part of your problem is that your focus is
too short.  It sounds like you're asking how to write different specs
for various lines of the _internals_ of this method.  That's too
fine-grained.  Spec the method from the _outside:_ write specs that
say "If I give the method these inputs, this should happen."  Then
test that the end result of the method's execution was what you

I'm betting that probably sounds really difficult, given the "complex
logic" you're describing.  And that would be my second, more important
tip: if your method is so complicated that you can't spec it from the
outside, you should take that as a sign.  Spaghetti code is usually
very hard to spec.

Reconsider your problem.  Try breaking it down into smaller, more
easily specified pieces, and then recompose them into the logic that
you need.  I don't know your business rules; it looks to me like the
basic task here is "Keep twiddling with the database until I get what
I'm looking for, as many times as that takes."  I don't know why
that's necessary, but if it is, recursion doesn't seem like the most
elegant answer to me.  Recursive calls are usually made in small
functions that don't have side effects.  This is the opposite.

What would I do instead?  Again, without knowing your specific
business, I'd probably break it into pieces, and then turn the
requirement inside out and do it with a loop:

def self.find_something(inputs)
  <find something in db based on inputs>

def self.add_something(inputs)
  <add something to db based on inputs>

And then, wherever you *would* have called mymethod(inputs), you can
instead write this, which will loop zero or more times:

add_something_to_db(inputs) until x = find_something(inputs)

...Whether or not you still want to wrap that in a method probably
depends on whether you need to call it more than once.  But I'll bet
you that the "add_something" and "find_something" methods are both
easier to spec from the outside.  If they're still too complex, then
break them down too.

Oh, and final trivia note:

> any thoughts on how to accomplish this?  two approaches that would make
> sense but don't seem to be possible as far as i know are:
> (A)  stub out the do_something method for any instance of the class (i can't
> stub it out for a particular record because the records don't exist at the
> time of calling the method and I'm not stubbing the creation process)
> (B)  stub out "mymethod" only for the second time it is called (obviously i
> can't stub the method out entirely since that's the method i'm testing)

You can do both of these with the Mocha mocking library, if you really
want to.  It puts an "any_instance" method on Class that you can use
to mock or stub; and you can specify ordered chains of results to

But again, you shouldn't need to if your methods are atomic enough.
If 'do_something' properly belongs outside the scope of what you're
testing, then maybe that's a sign that you shouldn't put it in the
same block of code.  And if you find a need to declare that your
method should behave entirely differently on a second invocation,
maybe it shouldn't be one method.

Simplify relentlessly.  Once I figured out how to make my code
simpler, I found that I wasn't mocking nearly as much as I used to.

Have Fun,
   Steve Eley (sfeley at gmail.com)
   ESCAPE POD - The Science Fiction Podcast Magazine

More information about the rspec-users mailing list