[rspec-users] Odd parameter munging with with()

James Hughes hughes.james at gmail.com
Mon Feb 19 16:32:45 EST 2007


Hi again,

On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote:
>
>  James,
>
>  the gem is converting your hash to an array of arrays when it builds the
> mock expectation.  This is really an artifact of Ruby's hash/array handling
> - the code in the gem looks perfectly reasonable, it just has this
> side-effect.
>
>  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.
>
>  Try this in irb:
>
>  $ irb
> irb(main):001:0> @params = {:cn => "Bilbo Baggins", :telephoneNumber =>
> "416-277-4418", :mail => "bilbo at baggins.com"}
>
>  irb(main):002:0> @params.collect{|c| c}
>  => [[:cn, "Bilbo Baggins"], [:telephoneNumber, "416-277-4418"], [:mail,
> "bilbo at baggins.com"]]
>  irb(main):003:0>
>
>  and you will see that your hash has been converted into the array of
> arrays.  That's what happening in the gem once you strip away
> #convert_constraint() etc.
>
>  You have a choice of workarounds; the simplest of which is a separate array
> @params_for_mock_user = @params.collect ; (null body returns each element as
> above) and then
> User.should_receive(:update_attributes).with(@params_for_mock_user).

Ok, this works (once I figured out that you have to send the
@params_for_mock_user with the post as well, duh;), but I have another
method that does this:

    user_klass = params[:user].delete(:ou).capitalize.constantize
    @user = user_klass.create(params[:user])

When the spec runs I'm calling delete on an array instead of the
expected hash, which returns nil. Jerry, you mentioned a choice of
workarounds: anything come to mind that might work around this?
>
>  It might be worth filing an RFE on this as it's counter-intuitive and
> likely to bite others as well
>

I'm writing this up right now..

James


>  James Hughes wrote:
>
> Hi,
>
> I have this setup block:
>
>  setup do
>  session[:login] = 'jhughes'
>  @user = mock("user")
>  User.stub!(:find).and_return(@user)
>  @params = {:cn => "Bilbo Baggins",
>  :telephoneNumber => "416-277-4418",
>  :mail => "bilbo at baggins.com"}
>  end
>
> And then 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
>
> This fails like this:
>
> 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"})
>
> Puzzling, especially since inspecting the @params variable just before
> the should_receive shows the expected hash.
>
> What am I doing wrong?
>
> James
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list