Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Newbie surprises with mock! and stub! #39

Open
wincent opened this issue Jul 1, 2010 · 2 comments
Open

Newbie surprises with mock! and stub! #39

wincent opened this issue Jul 1, 2010 · 2 comments
Labels

Comments

@wincent
Copy link
Contributor

wincent commented Jul 1, 2010

Just started using RR a couple days ago, so this may be a little dumb, but I had some surprises with the behavior of the "mock!" and "stub!" methods which I will try to summarize here:

First surprise is that this doesn't work:

my_stub_object = stub!.hello
my_stub_object.hello # => NoMethodError (undefined method 'hello')

So, the docs tell us about the subject() method:

my_stub_object = stub!.hello.subject
my_stub_object.hello # => works

Ok. Second surprise, then, is that here no "subject()" call needed:

stub(object).foo {stub!.bar}
object.foo.bar # => works

This is surprising because "stub(object).foo {something}" means "stub the foo method on object to return something", and that "something" is "stub!.bar". From the first example I would expect "stub!.bar" to return something that will raise a NoMethodError if I send it a "bar" message, unless I instead write it as "stub!.bar.subject". But no, it works.

(Evidently some magic is going on there, either in the stub! method defined within the context of the block, or the surrounding code which yields to the block itself... haven't dug into it yet.)

It's not clear why you can do:

stub(a).foo.stub!.bar.stub!.baz
a.foo.bar.baz # => works

But not:

a = stub!.foo.stub!.bar.stub!.baz
a.foo.bar.baz # => NoMethodError (undefined method 'foo')

The surprise here is that "stub!" calls can be chained, but not if the "stub!" call is the first link in the chain.

Likewise, you'll fail if you try this:

a = stub!.foo.subject
a.stub!.bar # => NoMethodError (undefined method 'stub!')

Or this:

a = stub!.foo.stub!.bar.stub!.baz.subject
a.foo.bar.baz # => NoMethodError (undefined method 'foo')

So I understand that "stub!()" is generally returning a double definition instance so that additional calls can be chained onto it, but I'm wondering if some of these little surprises could be avoided.

For example, could the first surprise be avoided by having:

my_stub_object = stub!.hello

Return the subject? (Obviously the subject itself would need methods like "stub!" itself mixed into it in order to permit chaining.) Or a version of double definition that responds to the "hello" method?

It seems that fixing that would also fix this:

a = stub!.foo.stub!.bar.stub!.baz

Because at each step of the chain, including the first one, we would return an object that understood both the stubbed method and other chaining methods such as "stub!" itself. (Not sure whether this would open up a can of worms in the case of "mock!").

Anyway, like I said, sorry if these are all dumb questions, but this is really the first place in RR where I've found myself surprised by its behavior. Everywhere else the interface has been rather intuitive.

Cheers,
Wincent

@jg
Copy link

jg commented Aug 15, 2012

+1. Those are real inconsistencies! What's even worse - there is almost no mention of this in the README. I've wasted a good deal of time fighting with rr syntax.

@mcmire
Copy link
Collaborator

mcmire commented Mar 15, 2013

Sorry for the late reply on this, I am starting to whip this thing into shape. I tend to use obj = Object.new; stub(obj).whatever because I can never figure out how #stub! works. I don't really have an immediate answer for this so I'll have to look into it. I can at least add something to the README, yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants