Rspec controller action list


#1

This action will list all the articles according to city. Please, can
some one guide me through this spec.

def list
@articles = find_city.articles.paginate :all, :page => params[:page]
, :order
=> “live_on DESC”, :conditions => { :type_for => “blog” }
end

it “should list all articles” do
get :list
controller.stub!(:find_city)
controller.should_receive(:find_city)
controller.stub!(:articles)
controller.should_receive(:articles)

articles.should_receive(:paginate).and_return(@articles)
response.should render_template('articles/list')

end

I get the following error when I run the spec.

NameError in ‘ArticlesController should list all articles’
undefined local variable or method `articles’ for
#<Spec::Rails::Example::Contro
llerExampleGroup::Subclass_1:0xa7b57dc>
spec/controllers/articles_controller_spec.rb:212:
spec/controllers/articles_controller_spec.rb:3:


#2

On Thu, Feb 28, 2008 at 3:54 AM, Namrata T. removed_email_address@domain.invalid
wrote:

This action will list all the articles according to city. Please, can
some one guide me through this spec.

def list
@articles = find_city.articles.paginate :all, :page => params[:page]

This line has what we call a train wreck. Don’t be alarmed! It sounds
dramatic, but that’s a common term for a series of objects strung
together with dots:

find_city returns the first object, on which articles gets called.
articles returns the second object, on which paginate is called.

As soon as you have that second dot you have a train wreck.

More below …

, :order
=> “live_on DESC”, :conditions => { :type_for => “blog” }
end

it “should list all articles” do
get :list

Here the action is called before setting up all the expectations. When
using mocks and stubs, they have to be set up before the action.

controller.stub!(:find_city)

Because the code has find_city returning an object, the stub has to
return an object. Because the object returned by find_city gets sent
paginate, it must be able to respond to that so it needs to either be
the kind of object (an AssociationProxy) or a substitute.

controller.should_receive(:find_city)
controller.stub!(:articles)
controller.should_receive(:articles)

articles.should_receive(:paginate).and_return(@articles)
response.should render_template('articles/list')

end

Given the code above, the spec needs to do this:

articles = mock(“articles”)
articles.should_receive(:paginate).
with(order => “live_on DESC”, :conditions => { :type_for => “blog” })
controller.should_receive(:find_city).and_return(articles)
get :list

HTH,
David


#3

Thanks Mr David for your reply. This gives me a better understanding of
so called train wreck. I am still facing problems with this spec.
firstly - I think I need to put a colon before order(e.g. :order=>
“live_on DESC”)

#list
it “should list all articles” do
articles = mock(“articles”)
articles.should_receive(:paginate).with(:order => “live_on DESC”,
:conditions => { :type_for => “blog” })
controller.should_receive(:find_city).and_return(articles)
get :list
end

but this gives me the following error
Spec::Mocks::MockExpectationError in ‘ArticlesController should list all
article
s’
Mock ‘ArticlesController’ expected :find_city with (any args) once, but
received
it 0 times
spec/controllers/articles_controller_spec.rb:3:

Thanks,
Namrata.


#4

It has to do with your “find_city” method. You spec is expecting it to
be
called from controller, hence:

controller.should_receive(:find_city)

Where is that method and why isn’t it being called should be your next
questions based on the code and spec you’ve pasted.

Hope that helps, buddy.

On Thu, Feb 28, 2008 at 10:27 PM, Namrata T. removed_email_address@domain.invalid
wrote:

controller.should_receive(:find_city).and_return(articles)
it 0 times


Bryan R.
http://www.bryanray.net

“Programming today is a race between software engineers striving to
build
bigger and better idiot-proof programs, and the Universe trying to
produce
bigger and better idiots. So far, the Universe is winning.”


#5

Bryan R. wrote:

It has to do with your “find_city” method. You spec is expecting it to
be
called from controller, hence:

controller.should_receive(:find_city)

Where is that method and why isn’t it being called should be your next
questions based on the code and spec you’ve pasted.

The method find_city is in application controller. I think the method
‘find_city’ is being called but its expecting some args.

Thanks,
Namrata.


#6

Matthias Hennemeyer wrote:

Am 03.03.2008 um 04:38 schrieb Namrata T.:

The method find_city is in application controller. I think the method
‘find_city’ is being called but its expecting some args.

The message:

Mock ‘ArticlesController’ expected :find_city with (any args) once, but
received
it 0 times

means that the method find_city was not called.

If the original method expects args or not doesn’t matter.
Because should_receive works as both an expectation and a stub, the
original method will not be called and no ArgumentError will be raised.

Okaayyy!
Then can you also please say why its not calling this :find_city method?

Thx,
Namrata.


#7

Am 03.03.2008 um 04:38 schrieb Namrata T.:

The method find_city is in application controller. I think the method
‘find_city’ is being called but its expecting some args.

The message:

Mock ‘ArticlesController’ expected :find_city with (any args) once, but
received
it 0 times

means that the method find_city was not called.

If the original method expects args or not doesn’t matter.
Because should_receive works as both an expectation and a stub, the
original method will not be called and no ArgumentError will be raised.


#8

On Mon, Mar 3, 2008 at 5:04 AM, Namrata T. removed_email_address@domain.invalid
wrote:

it 0 times

means that the method find_city was not called.

If the original method expects args or not doesn’t matter.
Because should_receive works as both an expectation and a stub, the
original method will not be called and no ArgumentError will be raised.

Okaayyy!
Then can you also please say why its not calling this :find_city method?

If the code is the same as it was in the first post in this thread,
it’s because the action is taking place before setting the
expectations.


#9

If the code is the same as it was in the first post in this thread,
it’s because the action is taking place before setting the
expectations.

Yes, it is the same. As you have suggested earlier.
I am pasting the spec again.

#list
it “should list all articles” do
articles = mock(“articles”)
articles.should_receive(:paginate).with(:order => “live_on DESC”,
:conditions => { :type_for => “blog” })
controller.should_receive(:find_city).and_return(articles)
response.should be_success
get :list

end

Thx,
Namrata.


#10

On Mon, Mar 3, 2008 at 5:22 AM, Namrata T. removed_email_address@domain.invalid
wrote:

#list
it “should list all articles” do
articles = mock(“articles”)
articles.should_receive(:paginate).with(:order => “live_on DESC”,
:conditions => { :type_for => “blog” })
controller.should_receive(:find_city).and_return(articles)
response.should be_success
get :list

end

That is NOT the same :slight_smile: In the initial post the first line was ‘get
:list’ - now that is the last line. So while you’re at it, please post
the action again as well.


#11

On Mon, Mar 3, 2008 at 11:21 PM, Namrata T. removed_email_address@domain.invalid
wrote:

it “should list all articles 2” do
articles = mock(“articles”)
get :list

Whoa. A couple of posts ago you said the action (get :list) was the
last thing. Now it’s not anymore. When dealing with mocks and stubs,
order is very important, which is why I asked you where the action
was. Message expectations (mocks) and stub values MUST be set before
the action.

controller.should_receive(:find_city).and_return(articles)

The implementation is find_city.articles, so find_city needs to return
something that owns articles.

controller.should_receive(:articles)

This one is just wrong - it’s the return value of find_city that
should receive articles.

articles.should_receive(:paginate).with(:order => "live_on DESC",

:conditions => { :type_for => “blog” })

This one is right, but again, needs to happen before the action.

response.should render_template('articles/list')

This one is correct, and in the correct place (after the action).

end

I am stubbing find_city and articles during set up

before_post do
controller.stub!(:find_city)

Here find_city will not return anything, so it’ll blow up on
find_city.articles …

controller.stub!(:articles)
end

Is this right?

Here’s what you want: http://pastie.caboo.se/161001

HTH,
David


#12

Followed your example! Still getting the following error -
Spec::Mocks::MockExpectationError in ‘ArticlesController should list all
article
s’
Mock ‘ArticlesController’ expected :find_city with (any args) once, but
received
it 0 times
spec/controllers/articles_controller_spec.rb:3:

Thanks,
Namrata


#13

Here is the action -
def list
@articles = find_city.articles.paginate :all, :page =>
params[:page] , :order => “live_on DESC”, :conditions => { :type_for
=> “blog” }
end

and the spec -

it “should list all articles 2” do
articles = mock(“articles”)
get :list

controller.should_receive(:find_city).and_return(articles)
controller.should_receive(:articles)

articles.should_receive(:paginate).with(:order => "live_on DESC", 

:conditions => { :type_for => “blog” })
response.should render_template(‘articles/list’)
end

I am stubbing find_city and articles during set up

before_post do
controller.stub!(:find_city)
controller.stub!(:articles)
end

Is this right?


#14

Phillip K. wrote:

Namatra,

Sorry, I spelled your name wrong.

Namrata

Peace,
Phillip


#15

I’m a complete rSpec newbie, so I might be stepping in somewhere that I
don’t belong, but…

Namatra, you said earlier that you were stubbing during setup, and you
shared the before_post method. In the spec, though, you are going a
:get. I’m not familiar with testing controllers yet (just getting into
that today, in fact), so I don’t know if there is a before_get. Could
that be part of your problem: confusing GETs and POSTs?

Peace,
Phillip