Search code examples
rspecrspec2rspec-railsstub

rspec-spies inspect the call arguments to stubbed methods and method spies


I'm using rspec-spies and am wondering if there's a way to inspect a spy after all the calls have been made.

For example, If I do something like

# setup
Post.stub(:find).with(@post.id).and_return(@post)

do_something_to_call_post_find()

# verify find was called
Post.should have_received(:find).with(@post.id)

This works great, but if Post didn't receive the expected argument, I get an unhelpful error message (basically "Post should have received find with 123"). Instead, I'd like to see what the actual calls to `find were.

I can pause right after do_something_to_call_post_find(), but is there a way to list all the calls / arguments to a stub/spy?

Actual use case This one caught me up today -- I was expecting Post.should have_received(:find).with(@post.id), where @post.id is an integer, my controller test passes the params (including the id) as a string. If I could have inspected the actual calls, I would have seen the difference between 123 and "123" and it would have been obvious.


Solution

  • This shortfall is no longer an issue in rspec 2.14.0.rc1, which incorporates the improved rspec-spies functionality and is available now on github.

    For example, executing the following spec:

    class Foo
      def self.bar(arg)
      end
    end
    
    describe "test" do
      it "should show differences" do
        Foo.stub(:bar)
        Foo.bar(123)
        Foo.should have_received(:bar).with('123')
      end
    end
    

    generates the following output:

    F
    
    Failures:
    
      1) test should show differences
         Failure/Error: Foo.should have_received(:bar).with('123')
           <Foo (class)> received :bar with unexpected arguments
             expected: ("123")
                  got: (123)
         # ./foo_spec.rb:10:in `block (2 levels) in <top (required)>'
    
    Finished in 0.00082 seconds
    1 example, 1 failure
    
    Failed examples:
    
    rspec ./foo_spec.rb:7 # test should show differences
    Peters-MacBook-Air-2:botmetrics palfvin$ 
    

    Update: Based on an examination of the definition of the have_received matcher at https://github.com/technicalpickles/rspec-spies/blob/master/lib/rspec-spies.rb and some informal testing, it appears that the messages received can be accessed programmatically as follows:

    Foo.__send__(:__mock_proxy).instance_variable_get("@messages_received")
    

    where Foo is your test double.