[rspec-devel] [ rspec-Bugs-8302 ] Strange side effect when mocking a class method

noreply at rubyforge.org noreply at rubyforge.org
Tue Jan 30 18:27:51 EST 2007


Bugs item #8302, was opened at 2007-01-30 02:35
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=8302&group_id=797

Category: mock module
Group: None
Status: Closed
Resolution: Accepted
Priority: 3
Submitted By: Tobias Grimm (e-tobi)
Assigned to: David Chelimsky (dchelimsky)
Summary: Strange side effect when mocking a class method

Initial Comment:
Hi!

This one is really driving me mad:

    class Foo
        def Foo.bar(arg)
        end
    end

    context "Context" do
        specify "spec 1" do
            Foo.should_not_receive(:bar).with(Array.new)
        end

        specify "spec 2" do
            Foo.bar(Array.new)
        end
    end

Running these specs results in this failure:

    ArgumentError in 'Context 1 spec 1.2'
    wrong number of arguments (0 for 1)
    ./xxx_controller_spec.rb:14:in `bar'
    ./xxx_controller_spec.rb:14:in `bar'
    ./xxx_controller_spec.rb:12:

    Finished in 0.002342 seconds


If I comment out the mocking of bar() in spec 1 it works. If I pass a string instead of an empty array in spec 1.2 it works too. I also can add a default value for the arg parameter in bar() and it will work. But in the above constellation, it doesn't work.

Maybe there's something going wrong with the define_method() call in the MockHandler class, that puts the original method of the mocked class back in place. This might also be a Ruby bug - I'm not sure.

Any ideas?

bye,

Tobias


----------------------------------------------------------------------

>Comment By: Tobias Grimm (e-tobi)
Date: 2007-01-30 23:27

Message:
Thanks a million! I've tested the last revision and it works
fine now!

----------------------------------------------------------------------

Comment By: David Chelimsky (dchelimsky)
Date: 2007-01-30 22:34

Message:
Turns out that this is a problem for instance methods as well - we just never noticed it because typically each spec is dealing with its own instances.

Whether or not this is a Ruby bug is hard to say. We had been storing proxied methods in a Hash w/ the method name as a key and then restoring them back to the object.

The fix, which inadvertently also fixed bug 7611, was to use alias_method on the way in and out. In other words, based on your example above, when you call:

Foo.should_receive(:bar)

the MockHandler is now aliasing :bar with :bar__proxied_by_rspec (using alias_method, so it actually makes a copy) and redefining :bar to intercept calls.

When the spec is over, the alias is reversed and the munged name is removed.

Fixed in rev 1447

----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=8302&group_id=797


More information about the rspec-devel mailing list