Forum: RSpec Route is valid but not found :(

F80c5168b92fe9d49b0668cde3bdd57c?d=identicon&s=25 ct9a (Guest)
on 2011-08-22 08:16
(Received via mailing list)
Hi, guys,

  After reading the rspec book (dec 2010 edition), I went on to write
controller specs for an application I'm porting over from rails 2.3.x
to rails 3.


1) I ran 'rake routes' and got the following:

    parts GET    /parts(.:format)
{:action=>"index", :controller=>"parts"}
          POST   /parts(.:format)
{:action=>"create", :controller=>"parts"}
 new_part GET    /parts/new(.:format)
{:action=>"new", :controller=>"parts"}
edit_part GET    /parts/:id/edit(.:format)
{:action=>"edit", :controller=>"parts"}
     part GET    /parts/:id(.:format)
{:action=>"show", :controller=>"parts"}
          PUT    /parts/:id(.:format)
{:action=>"update", :controller=>"parts"}
          DELETE /parts/:id(.:format)
{:action=>"destroy", :controller=>"parts"}

2) I ran 'rake spec:controllers' and got the error below.

Pending:
  PartsController the new part object's updates are saved successfully
saves updates to a new part
    # Not Yet Implemented
    # ./spec/controllers/parts_controller_spec.rb:59

Failures:

  1) PartsController saves updates to an existing part object
successfully
     Failure/Error: put :update#, :part => { 'title' => 'Grimspeed' }
     ActionController::RoutingError:
       No route matches {:controller=>"parts", :action=>"update"}
     # ./spec/controllers/parts_controller_spec.rb:55

3) Here's what the spec reads:

    it 'saves updates to an existing part object successfully' do
        Part.should_receive(:update).
            with( 'title' => 'Brake pads' ).
            and_return(part)
        put :update#, :part => { 'title' => 'Brake pads' }
    end




What I do not understand is that
the :controller=>"parts", :action=>"update" route actually exists
(when I ran "rake routes") but the tests does not acknowledge the
existence of the 'update' method in the controller with PUT request.
1df9fc8ddf084661265bbae74a8d0b43?d=identicon&s=25 Justin Ko (Guest)
on 2011-08-22 09:44
(Received via mailing list)
On Mon, Aug 22, 2011 at 12:14 AM, ct9a <anexiole@gmail.com> wrote:

> {:action=>"index", :controller=>"parts"}
>          POST   /parts(.:format)
> {:action=>"create", :controller=>"parts"}
>  new_part GET    /parts/new(.:format)
> {:action=>"new", :controller=>"parts"}
> edit_part GET    /parts/:id/edit(.:format)
> {:action=>"edit", :controller=>"parts"}
>     part GET    /parts/:id(.:format)
> {:action=>"show", :controller=>"parts"}
>          PUT    /parts/:id(.:format)
>

The :id means you need to pass an "id" to the route helper method.


>    # ./spec/controllers/parts_controller_spec.rb:59
> 3) Here's what the spec reads:
>
>    it 'saves updates to an existing part object successfully' do
>        Part.should_receive(:update).
>            with( 'title' => 'Brake pads' ).
>            and_return(part)
>        put :update#, :part => { 'title' => 'Brake pads' }
>    end
>

So you need to "find" the part first:

part = double('part')
Part.should_receive(:find).with(1).and_return(part)
Part.should_receive(:update).with('title' => 'Brake
pads').and_return(part)
put :update, :id => 1, :part => {'title' => 'Brake pads'}



>
>
>
>
> What I do not understand is that
> the :controller=>"parts", :action=>"update" route actually exists
> (when I ran "rake routes") but the tests does not acknowledge the
> existence of the 'update' method in the controller with PUT request.
>

You need to pass in the :id for Rails to recognize the route.
F80c5168b92fe9d49b0668cde3bdd57c?d=identicon&s=25 ct9a (Guest)
on 2011-08-23 05:52
(Received via mailing list)
Thanks, Justin.

I have the part object mocked up before each spec runs.

------- Extract begins -----------------

    let(:part){
        mock_model('Part').as_null_object
    }

    before do
        Part.stub(:new).and_return(part)
    end

------- Extract ends -----------------


With that in mind, I just made changes to my spec as below:

------- Extract begins -----------------

    it 'saves updates to an existing part object successfully' do
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update).with( 'title' =>
'Grimspeed' ).and_return(part)
        put :update, :id => 1, :part => { 'title' => 'Grimspeed' }
    end

------- Extract ends -----------------


When I run the 'rake spec:controllers', I get the following error:


------- Error extract begins -----------------

  1) PartsController saves updates to an existing part object
successfully
     Failure/Error: Part.should_receive(:update).with( 'title' =>
'Brake pads' ).and_return(part)
       (<Part(id: integer, title: string, description: text,
created_by: string, updated_by: string, created_at: datetime,
updated_at: datetime) (class)>).update({"title"=>"Brake pads"})
           expected: 1 time
           received: 0 times
     # ./spec/controllers/parts_controller_spec.rb:53

------- Error extract ends -----------------

I then put in Justin's change with the use of double() as follows:

------- Source code extract begins -----------------

    it 'saves updates to an existing part object successfully' do
        part = double(part)
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update).with( 'title' => 'Brake
pads' ).and_return(part)
        put :update, :id => 1, :part => { 'title' => 'Brake pads' }
    end

------- Source code extract ends -----------------

and I got the following error:

------- Error extract begins -----------------

  1) PartsController saves updates to an existing part object
successfully
     Failure/Error: put :update, :id => 1, :part => { 'title' =>
'Brake pads' }
       Double received unexpected message :update_attributes with
({"title"=>"Brake pads"})
     # ./app/controllers/parts_controller.rb:63:in `update'
     # ./app/controllers/parts_controller.rb:62:in `update'
     # ./spec/controllers/parts_controller_spec.rb:55

------- Error extract ends -----------------

I have also looked at a few other posts in the group but can't figure
out what's causing
update_attributes not to be recognised :(

-
http://groups.google.com/group/rspec/browse_thread...
-
http://groups.google.com/group/rspec/browse_thread...

My update message in the parts controller reads as below:

------- Source code extract starts -----------------
  def update
    @part = Part.find(params[:id])

    respond_to do |format|
      if @part.update_attributes(params[:part])
        format.html { redirect_to(@part, :notice => 'Part was
successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @part.errors, :status
=> :unprocessable_entity }
      end
    end
  end

------- Source code extract ends -----------------


I have used this bit of code without problems in the past.
update_attributes, like save, is part of the ActiveRecord api (http://
ar.rubyonrails.org/).

Well, given that controllers are not to know of the implementation of
messages,
I have then stubbed the message to the update_attributes method in the
parts controller.

------- Source code extract starts -----------------
    context 'saves updates to an existing part object successfully' do
        before do
            part =
double('part').stub(:update_attributes).and_return(true)
        end

        it 'does its job in saving the update' do
            Part.should_receive(:find).with(1).and_return(part)
            Part.should_receive(:update).with('title' => 'Brake
pads').and_return(part)
            put :update, :id => 1, :part => {'title' => 'Brake pads'}
        end
    end
------- Source code extract ends -----------------

Alas, I got the error below :(

------- Error extract starts -----------------

  1) PartsController saves updates to an existing part object
successfully does its job in saving the update
     Failure/Error: Part.should_receive(:update).with('title' =>
'Brake pads').and_return(part)
       (<Part(id: integer, title: string, description: text,
created_by: string, updated_by: string, created_at: datetime,
updated_at: datetime) (class)>).update({"title"=>"Brake pads"})
           expected: 1 time
           received: 0 times
     # ./spec/controllers/parts_controller_spec.rb:61

------- Error extract ends -----------------
1df9fc8ddf084661265bbae74a8d0b43?d=identicon&s=25 Justin Ko (Guest)
on 2011-08-23 05:58
(Received via mailing list)
On Mon, Aug 22, 2011 at 9:09 PM, ct9a <anexiole@gmail.com> wrote:

>    }
> ------- Extract begins -----------------
>
>    it 'saves updates to an existing part object successfully' do
>         Part.should_receive(:find).with(1).and_return(part)
>        Part.should_receive(:update).with( 'title' =>
> 'Grimspeed' ).and_return(part)
>

Should be:

Part.should_receive(:update_attributes).with('title' =>
'Grimspeed').and_return(part)

No where do you call `update` on Part.
F80c5168b92fe9d49b0668cde3bdd57c?d=identicon&s=25 ct9a (Guest)
on 2011-08-23 06:16
(Received via mailing list)
On Aug 23, 1:55pm, Justin Ko <jko...@gmail.com> wrote:
> >  }
>
> No where do you call `update` on Part.
Yes, I have done that and the spec looks like below.

------------------ Spec extract begins
------------------------------------------
    context 'saves updates to an existing part object successfully' do
        it 'does its job in saving the update' do
            Part.should_receive(:find).with(1).and_return(part)
            Part.should_receive(:update_attributes).with('title' =>
'Brake pads').and_return(part)
            put :update, :id => 1, :part => {'title' => 'Brake pads'}
        end
    end
------------------ Spec extract ends
------------------------------------------

Alas, it's still giving out an error indicating the update_attributes
message is never called.
I've already got a put request to the 'update' method with an id and
the part hash parameter
and yet it looks like 'update' is not called (which in will call
update_attributes in it).

----------------- Error extract starts
-------------------------------------------------

  1) PartsController saves updates to an existing part object
successfully does its job in saving the update
     Failure/Error:
Part.should_receive(:update_attributes).with('title' => 'Brake
pads').and_return(part)
       (<Part(id: integer, title: string, description: text,
created_by: string, updated_by: string, created_at: datetime,
updated_at: datetime) (class)>).update_attributes({"title"=>"Brake
pads"})
           expected: 1 time
           received: 0 times
     # ./spec/controllers/parts_controller_spec.rb:54

Finished in 0.25483 seconds
8 examples, 1 failure, 1 pending

----------------- Error extract end
1df9fc8ddf084661265bbae74a8d0b43?d=identicon&s=25 Justin Ko (Guest)
on 2011-08-23 14:02
(Received via mailing list)
Sent from my iPhone

On Aug 22, 2011, at 10:14 PM, ct9a <anexiole@gmail.com> wrote:

>>
>>> With that in mind, I just made changes to my spec as below:
>> Part.should_receive(:update_attributes).with('title' =>
>            Part.should_receive(:find).with(1).and_return(part)
> I've already got a put request to the 'update' method with an id and
> Part.should_receive(:update_attributes).with('title' => 'Brake
> 8 examples, 1 failure, 1 pending
>
> ----------------- Error extract end
> -------------------------------------------------
>
> Hmm.... What is missing?

Do you have a before filter somewhere that is preventing the
:update_attributes message from being received?
F80c5168b92fe9d49b0668cde3bdd57c?d=identicon&s=25 Gordon Yeong (Guest)
on 2011-08-23 14:46
(Received via mailing list)
>
>
>  Do you have a before filter somewhere that is preventing the
> :update_attributes message from being received?
>
> I have checked my application's controllers
(app/controllers/application_controller.rb and
 app/controllers/parts_controller.rb) and controller spec
(spec/controllers/parts_controller_spec.rb) and found no before filter
that
is preventing the :update_attributes message from being received by
Parts.

Below is what my spec/controllers/parts_controller_spec.rb looks like:

------- Source code, spec/controllers/parts_controller_spec.rb starts
-----------------------

require 'spec_helper'

describe PartsController do
    let(:part){
        mock_model('Part').as_null_object
    }

    before do
        Part.stub(:new).and_return(part)
    end

    it "creates a new part" do
        Part.should_receive(:new).
            with('title' => 'HKS boost controller').
            and_return(part)
        post :create, :part => { 'title' => 'HKS boost controller' }
    end

    context "saves the new part object successfully" do
        it "sets the flash with a success message" do
            post :create
            flash[:notice].should eq('Part was successfully created.')
        end

        it "redirects the user back to the Parts index page" do
            post :create
            response.should redirect_to( :action => 'index' )
        end
    end

    context "the new part object fails to save" do
        before do
            # sabotage and make the save fail
            part.stub(:save).and_return(false)
            # call the create method which will have save in its process
            post :create
        end

        it "assigns @part with the data from db (or a blank one if it's
the
first time" do
            assigns[:part].should eq(part)
        end

        it "renders the 'new' template again" do
            # test that the template, 'new' is rendered. Of course, for
this
            # work, the part's attribute variable values must be passed
to
the
            # view for rails to successfully render the template
            response.should render_template('new')
        end
    end

    context 'saves updates to an existing part object successfully' do
        it 'does its job in saving the update' do
            Part.should_receive(:find).with(1).and_return(part)
            Part.should_receive(:update_attributes).with('title' =>
'Brake
pads').and_return(part)
            put :update, :id => 1, :part => {'title' => 'Brake pads'}
            flash[:notice].should eq('Part was successfully updated.')
        end
    end

end

------- Source code, spec/controllers/parts_controller_spec.rb ends
F80c5168b92fe9d49b0668cde3bdd57c?d=identicon&s=25 Gordon Yeong (Guest)
on 2011-08-23 14:51
(Received via mailing list)
I found out why it was not working.

The line, 'Part.should_receive(:update_attributes).with('title' =>
'Brake
pads').and_return(part)' should not be there because the controller
specs
should not care about implementation (ie. how things are processed,
rather
just what is done).  I realised this when I looked at my specs for
creation
of new objects.

I commented the line and the spec now passes as expected.


------------ Spec extract starts -------------------------

    context 'saves updates to an existing part object successfully' do
        it 'does its job in saving the update' do
            Part.should_receive(:find).with(1).and_return(part)
        #   Part.should_receive(:update_attributes).with('title' =>
'Brake
pads').and_return(part)
            put :update, :id => 1, :part => {'title' => 'Brake pads'}
            flash[:notice].should eq('Part was successfully updated.')
        end
    end

------------ Spec extract ends  -------------------------

Thank you for your help, Justin!

Gordon Yeong :)
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2011-08-23 14:58
(Received via mailing list)
On Aug 23, 2011, at 7:22 AM, Gordon Yeong wrote:

>         it 'does its job in saving the update' do
>             Part.should_receive(:find).with(1).and_return(part)
>         #   Part.should_receive(:update_attributes).with('title' => 'Brake
pads').and_return(part)

^^ Change the class name Part to the variable part ^^:

  part.should_receive(:update_attributes).with('title' => 'Brake
pads').and_return(part)

It's the part object, not the Part class that will receive
update_attributes.

HTH,
David




> _______________________________________________
> rspec-users mailing list
> rspec-users@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

Cheers,
David
5d78498cf014ece6bf3460a4ee40c3b9?d=identicon&s=25 Kenrick Chien (kakashi)
on 2011-08-23 14:59
(Received via mailing list)
I think you were closer when you had:
------- Source code extract starts -----------------
   context 'saves updates to an existing part object successfully' do
       before do
           part =
double('part').stub(:update_
attributes).and_return(true)
       end

       it 'does its job in saving the update' do
            Part.should_receive(:find).with(1).and_return(part)
           Part.should_receive(:update).with('title' => 'Brake
pads').and_return(part)
           put :update, :id => 1, :part => {'title' => 'Brake pads'}
        end
   end
------- Source code extract ends -----------------

However, you were setting part equal to the return value from
"stub(:update_attributes).and_return(true)" which returns a Proc, not a
double.
Instead, try this:

let(:part) { double('part') }

   it 'does its job in saving the update' do
        part.stub(:update_attributes).and_return(true)  # <--- moved
this
from the before method

          Part.should_receive(:find).with(1).and_return(part)
           Part.should_receive(:update).with('title' => 'Brake
pads').and_return(part)
           put :update, :id => 1, :part => {'title' => 'Brake pads'}
        end
   end
1df9fc8ddf084661265bbae74a8d0b43?d=identicon&s=25 Justin Ko (Guest)
on 2011-08-23 15:00
(Received via mailing list)
On Tue, Aug 23, 2011 at 6:11 AM, Gordon Yeong <anexiole@gmail.com>
wrote:

> Below is what my spec/controllers/parts_controller_spec.rb looks like:
>
>
>     end
> first time" do
>         end
>     end
>
>     context 'saves updates to an existing part object successfully' do
>         it 'does its job in saving the update' do
>             Part.should_receive(:find).with(1).and_return(part)
>             Part.should_receive(:update_attributes).with('title' => 'Brake
> pads').and_return(part)
>

Oh duh. You're calling `should_receive(:update_attributes)` on `Part`
when
it should be called on `part`:

part.should_receive(:update_attributes).with('title' => 'Brake
pads').and_return(true)
1df9fc8ddf084661265bbae74a8d0b43?d=identicon&s=25 Justin Ko (Guest)
on 2011-08-23 15:41
(Received via mailing list)
On Tue, Aug 23, 2011 at 6:22 AM, Gordon Yeong <anexiole@gmail.com>
wrote:

> I found out why it was not working.
>
> The line, 'Part.should_receive(:update_attributes).with('title' => 'Brake
> pads').and_return(part)' should not be there because the controller specs
> should not care about implementation (ie. how things are processed, rather
> just what is done).
>

Depends on what you want to do. Now, your controller spec is coupled to
your
model, so if "update_attributes" fails, your controller spec will fail
too.
This topic is locked and can not be replied to.