Forum: RSpec upgraded to rails 3.1.0 and found that string value of id has to be used instead of the integer valu

Posted by Gordon (Guest)
on 2011-10-25 09:33
(Received via mailing list)
My advance apologies if the title/subject is not too descriptive.


Pre: I have just upgraded from rails 3.0.9 to rails 3.1.0

Before the upgrade, running 'rake spec' sees all my specs pass.

After the upgrade, I seem to encounter some errors:
-------------- Error extracts start -------------------------------
controller_spec.rb ./spec/controllers/parts_controller_spec.rb
............................FFF

Failures:

  1) PartsController saves updates to an existing part object
successfully by finding the existing part and returning it for update
     Failure/Error: put :update, :id => "1", :part => {
       <Part(id: integer, title: string, description: text,
created_by: integer, updated_by: integer, created_at: datetime,
updated_at: datetime) (class)> received :find with unexpected
arguments
         expected: (1)
              got: ("1")
     # ./app/controllers/parts_controller.rb:131:in
`check_authorisation'
     # ./spec/controllers/parts_controller_spec.rb:74:in `block (3
levels) in <top (required)>'

  2) PartsController saves updates to an existing part object
successfully does its job in saving the update
     Failure/Error: put :update, :id => 1, :part => {
       <Part(id: integer, title: string, description: text,
created_by: integer, updated_by: integer, created_at: datetime,
updated_at: datetime) (class)> received :find with unexpected
arguments
         expected: (1)
              got: ("1")
     # ./app/controllers/parts_controller.rb:131:in
`check_authorisation'
     # ./spec/controllers/parts_controller_spec.rb:81:in `block (3
levels) in <top (required)>'

  3) PartsController saves updates to an existing part object
successfully communicates the successful update via the flash
     Failure/Error: put :update, :id => 1, :part => {'title' => 'Brake
pads'}
       <Part(id: integer, title: string, description: text,
created_by: integer, updated_by: integer, created_at: datetime,
updated_at: datetime) (class)> received :find with unexpected
arguments
         expected: (1)
              got: ("1")
     # ./app/controllers/parts_controller.rb:131:in
`check_authorisation'
     # ./spec/controllers/parts_controller_spec.rb:87:in `block (3
levels) in <top (required)>'

Finished in 8.02 seconds
31 examples, 3 failures

Failed examples:

rspec ./spec/controllers/parts_controller_spec.rb:72 # PartsController
saves updates to an existing part object successfully by finding the
existing part and returning it for update
rspec ./spec/controllers/parts_controller_spec.rb:79 # PartsController
saves updates to an existing part object successfully does its job in
saving the update
rspec ./spec/controllers/parts_controller_spec.rb:86 # PartsController
saves updates to an existing part object successfully communicates the
successful update via the flash
rake aborted!
-------------- Error extracts end  -------------------------------


My parts' controller spec reads:

------------ /spec/controllers/parts_controller_spec.rb start
-------------

 63     context 'saves updates to an existing part object
successfully' do
 64         @new_title = 'Brake pads'
 65
 66         before(:each) do
 67             @part = mock_model(Part, :update_attributes! =>
true, :created_by => @user.id)
 68             Part.stub!('check_authorisation').and_return(true)
 69             Part.stub!(:find).with(1).and_return(@part)
 70         end
 71
 72         it 'by finding the existing part and returning it for
update' do
 73             Part.should_receive(:find).with(1).and_return(@part)
 74             put :update, :id => "1", :part => {
 75                 'title' => @new_title
 76             }
 77         end
 78
 79         it 'does its job in saving the update' do
 80
@part.should_receive(:update_attributes!).and_return(true)
 81             put :update, :id => 1, :part => {
 82                 'title' => @new_title
 83             }
 84         end
 85
 86         it 'communicates the successful update via the flash' do
 87             put :update, :id => 1, :part => {'title' => 'Brake
pads'}
 88             flash[:notice].should eql('Part was successfully
updated.')
 89         end
 90     end

------------ /spec/controllers/parts_controller_spec.rb end
-------------

What I did:  By changing the argument value from 1 to '1' in the lines
that deal with the
a) stubbing of the find method (with a value of 1)
b) should_receive test

Here's how the lines look like after the change:

 69             Part.stub!(:find).with('1').and_return(@part)

 73             Part.should_receive(:find).with('1').and_return(@part)

The result is that all specs pass.

--------- Extract of run - start ----------------------

192-168-1-2:script anexiole$ rake spec:controllers
(in /Users/ct9a/projects/try_rails)
/usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby -S rspec ./spec/
controllers/application_controller_spec.rb ./spec/controllers/
brands_controller_spec.rb ./spec/controllers/home_controller_spec.rb ./
spec/controllers/parts_controller_spec.rb
...............................

Finished in 8.49 seconds
31 examples, 0 failures

--------- Extract of run - end ----------------------


I can't think of a good reason of why putting the quotes worked after
the upgrade to rails 3.1? It's worked fine all this while circa rails
3.1

Why should I have to pass a string of '1' instead of using the integer
value, 1 of the id to the stubbing definition for the find method (As
argument) and the expected id value in the should_receive test?

Would like to hear some thoughts on this behaviour.

Thank you


Gorodn Yeong
Posted by David Chelimsky (Guest)
on 2011-10-25 14:57
(Received via mailing list)
On Oct 25, 2011, at 1:56 AM, Gordon wrote:

> ............................FFF
>         expected: (1)
>              got: ("1")
>     # ./app/controllers/parts_controller.rb:131:in
> `check_authorisation'
>     # ./spec/controllers/parts_controller_spec.rb:74:in `block (3
> levels) in <top (required)>'

<snip/>

> I can't think of a good reason of why putting the quotes worked after
> the upgrade to rails 3.1? It's worked fine all this while circa rails
> 3.1

I can, but not because it's an rspec issue. I just happened to submit 
the patch to Rails that made this change. [1]

The problem is that Rails functional tests, which power rspec controller 
specs, don't go through rack. This means that you used to be able to do 
this in a controller spec:

it "does one thing if :some_number is > 5" do
  get :some_action, :some_number = 6
end

And this in the controller:

def some_action
  if params[:some_number] > 5
    do_this
  else
    do_that
  end
end

And the spec would pass, but it would fail when running through rack, as 
it does when you run a server. That's because all parameters are 
'to_param'd before they make it to a controller when running through 
rack, but they weren't getting the same treatment in Rails functional 
tests. This was true whether you were using rspec, minitest, test/unit, 
etc, and was happening because the Rails test framework was letting 
Fixnums in the specs make it directly to the controllers.

So the upside of this change is that we decrease the likelihood of false 
positives. The downside is that you have to change stubs and message 
expectations that are constrained on non-strings to expect strings. The 
upside of the downside is that your specs are now telling the truth, and 
are correctly aligned with the reality of the running application.

HTH,
David

[1] https://github.com/rails/rails/pull/1203
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.