[rspec-users] How to intercept an instance method from StdLib (1.9.2)

Matt Wynne matt at mattwynne.net
Sun Mar 6 05:58:03 EST 2011


On 6 Mar 2011, at 10:30, Hedge Hog wrote:

> On Sun, Mar 6, 2011 at 12:27 AM, Matt Wynne <matt at mattwynne.net> wrote:
>> 
>> On 5 Mar 2011, at 12:06, Hedge Hog wrote:
>> 
>>> On Fri, Mar 4, 2011 at 8:12 PM, Matt Wynne <matt at mattwynne.net> wrote:
>>>> 
>>>> On 4 Mar 2011, at 05:45, Hedge Hog wrote:
>>>> 
>>>>> Hi,
>>>>> I'm struggling with something that seems to be simple, and I've not
>>>>> had any joy following the RSpec books suggestions (p. 187).
>>>>> I'd like to test that a method raises and error when a file is not found.
>>>>> I've tried adding this in my example just before I call my method, but
>>>>> it never seems to get invoked.
>>>>> Pathname.stub(:exist?).and_return(false)
>>>> 
>>>> That's stubbing a class method.
>>>> 
>>>> exist? is an instance method so you need to stub the specific instance of pathname that's being used in your object-under-test, rather than the Pathname class.
>>>> 
>>> 
>>> Is there a (clean) way to intercept this instance and add the
>>> stub/mock to it?  What I see in the Rspec books suggests I'd have to
>>> force the Pathname instance to the surface, as some method argument.
>>> That feels all wrong - to have to change my method's interface just to
>>> test a behavior.
>>> 
>>> Appreciate any experience, comments or suggestions people may have.
>> 
>> You could try something like this:
>> 
>>    fake_pathname = double(Pathname, :exist? => false)
>>    Pathname.stub(:new).and_return(fake_pathname)
>> 
>> This is basically The Ruby Way of doing dependency injection.
> 
> Thank you Matt.  Not sure if I'm going mad but it seems the Rspec
> book, Ch 14, doesn't cover this use case in much detail.
> I appreciate it is an introductory book, so this may be out of scope.
> Alternatively: It may be that, reaching inside a method in this way is
> a 'test-smell' indicating some bad practice - I'm I being too
> sensitive?
> 
> TIA

In the Java / C# world, I'd be more used having to do something like this:

    fake_pathname = double(Pathname, :exist? => false)
    helper = B3::Bdd::Helpers.new(fake_pathname)

or even

    fake_pathname = double(Pathname, :exist? => false)
    fake_pathanme_factory = double("PathnameFactory", :new => fake_pathname)
    helper = B3::Bdd::Helpers.new(fake_pathname_factory)

Fortunately, this kind of thing just isn't necessary in Ruby.

The risk of doing what I've suggested above is that there are probably other legitimate ways of instantiating a Pathname (I don't know what they are, but I can imagine there could be some) and you might one day want to refactor your tested class to use one of those alternative ways. If you did, your test would break for no good reason, just because you were no longer hitting Pathname.new and so the stubs stopped working. However, .new is pretty idiomatic in Ruby, so you're normally safe.

> 
>> 
>>> 
>>>>> 
>>>>> The whole example:
>>>>> 
>>>>>    it "should raise an error if RVM's install root does not exist" do
>>>>>       Pathname.stub(:exist?).and_return(false)
>>>>>       lambda{ B3::Bdd::Helpers.rvm_path}.should
>>>>> raise_error(RuntimeError, "File not found:")
>>>>>    end
>>>>> 
>>>>> Appreciate any tips.
>>>>> 
>>>>> --
>>>>> πόλλ' οἶδ ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα
>>>>> [The fox knows many things, but the hedgehog knows one big thing.]
>>>>>   Archilochus, Greek poet (c. 680 BC – c. 645 BC)
>>>>> http://wiki.hedgehogshiatus.com
>>>>> _______________________________________________
>>>>> rspec-users mailing list
>>>>> rspec-users at rubyforge.org
>>>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>> 
>>>> cheers,
>>>> Matt
>>>> 
>>>> matt at mattwynne.net
>>>> 07974 430184
>>>> 
>>>> _______________________________________________
>>>> rspec-users mailing list
>>>> rspec-users at rubyforge.org
>>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>> 
>>> 
>>> 
>>> --
>>> πόλλ' οἶδ ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα
>>> [The fox knows many things, but the hedgehog knows one big thing.]
>>>   Archilochus, Greek poet (c. 680 BC – c. 645 BC)
>>> http://wiki.hedgehogshiatus.com
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>> 
>> cheers,
>> Matt
>> 
>> matt at mattwynne.net
>> 07974 430184
>> 
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
> 
> 
> 
> -- 
> πόλλ' οἶδ ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα
> [The fox knows many things, but the hedgehog knows one big thing.]
>   Archilochus, Greek poet (c. 680 BC – c. 645 BC)
> http://wiki.hedgehogshiatus.com

cheers,
Matt

matt at mattwynne.net
07974 430184



More information about the rspec-users mailing list