[rspec-devel] [ rspec-Feature Requests-8771 ] Spec::Mocks::BaseExpectation#with converts hash params to array of arrays with #collect

noreply at rubyforge.org noreply at rubyforge.org
Mon Feb 19 19:07:55 EST 2007


Feature Requests item #8771, was opened at 2007-02-20 00:07
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3152&aid=8771&group_id=797

Category: mock module
Group: None
Status: Open
Priority: 3
Submitted By: James Hughes (jpath)
Assigned to: Nobody (None)
Summary: Spec::Mocks::BaseExpectation#with converts hash params to array of arrays with #collect

Initial Comment:
This setup block:

setup do
     @user = mock("user")
     User.stub!(:find).and_return(@user)
     @params = {:cn => "Bilbo Baggins",
      :telephoneNumber => "416-277-4418",
      :mail => "bilbo at baggins.com"}
end

with this spec:

specify "should update and save the attributes for user" do
    @user.should_receive(:update_attributes).with(@params).and_return(true)
    post :update, :id => "jhughes", :user => @params
end

and this controller action:

  def update
    @user = User.find params[:id]
    @user.update_attributes params[:user]
    redirect_to :action => 'list'
  end

results in this failure: 

Mock 'user' expected :update_attributes with ([:telephoneNumber, "416-277-4418"], [:mail, "bilbo at baggins.com"], [:cn, "Bilbo Baggins"]) but received it with ({"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", "mail"=>"bilbo at baggins.com"
})

As pointed out by Jerry West on rspec-users, the hash that is passed to #with is getting Enumerable#collect called on it and converted to an array of arrays.
To quote Jerry: "If you check out $GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/message_expectation.rb you will see that #with() passes your hash to a new instance of ArgumentExpectation, which is defined in $GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/argument_expectation.rb .   There you will see that a hash is a LiteralArgConstraint (as opposed to :anything, :numeric, and the other parameters that #with() accepts).  The interesting code is around line 89 in #process_arg_constraints() where your hash is converted one item at a time using the normal Ruby Enumerable routine #collect().  Which is where the side-effect happens."

I'm running off of trunk, rev. 1514 as of this writing.

Note that I attempted to do a "bug reduction" with this, distilling things down to the simplest thing that would produce the same error (i.e. without all the rails stuff), and I couldn't get it to work. This is what I came up with:

class Test
  def Test.amethod params
    true
  end
end
context "passing a hash to #with" do
  specify "should pass a hash to #with" do
    @params = { :param1 => "foo",
      :param2 => "bar"}
    Test.should_receive(:amethod).with(@params).and_return(true)
    Test.amethod @params
  end
end

This passes. My rspec/mock object-fu is not sufficient to spot the difference between the two examples.



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

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


More information about the rspec-devel mailing list