On Mon, Jul 20, 2009 at 8:33 PM, Barun Singh<baru...@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 expect. 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> end def self.add_something(inputs) <add something to db based on inputs> end 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) x.do_something ...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 return. 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 (sfe...@gmail.com) ESCAPE POD - The Science Fiction Podcast Magazine http://www.escapepod.org _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users