Craig P Jolicoeur
2008-Sep-06 02:18 UTC
[rspec-users] issue with application controller spec
I''m having some trouble trying to spec some methods in my Rails
application controller.
I''m new to rspec converting over from straight test::unit.
Here is the method in my application.rb controller that I''m trying to
spec
def render_403
logger.debug "Returned 403: #{request.request_uri}"
render :file => "#{RAILS_ROOT}/public/403.html", :status =>
''403''
end
Here is my *current* spec
describe "handling render 403" do
before(:each) do
controller.request.should_receive(:request_uri).and_return(''response
request_uri'')
end
it "should render the 403 error page" do
controller.render_403
response.should render_file("#{RAILS_ROOT}/public/403.html")
end
it "should send a message to logger" do
@log_stream = StringIO.new
controller.stub!(:logger).and_return(Logger.new(@log_stream))
controller.render_403
@log_stream.string.should match(/Returned 403:/)
end
end
Both specifications fail with the following error:
You have a nil object when you didn''t expect it!
The error occurred while evaluating nil.template
/app/controllers/application.rb:25 :in `render_403''
/spec/controllers/application_controller_spec.rb:34
The errors is being raised on the render :file line of the render_403
method and I have no idea what it is referring too. If I comment out
that line, then my logger spec test passes fine but I need to
obviously test that the render happens and I can''t figure out this
error and google has provided no help.
On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote:> I''m having some trouble trying to spec some methods in my Rails > application controller. > > I''m new to rspec converting over from straight test::unit. > > Here is the method in my application.rb controller that I''m trying > to spec > > def render_403 > logger.debug "Returned 403: #{request.request_uri}" > render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' > end > > > Here is my *current* spec > > > describe "handling render 403" do > > before(:each) do > > controller.request.should_receive(:request_uri).and_return(''response > request_uri'') > endFirst off - should_receive *is* a test - why would you write a test in the setup?> > it "should render the 403 error page" do > controller.render_403 > response.should render_file("#{RAILS_ROOT}/public/403.html") > endTwo issues with this test: 1. Normally, if you are going to write a test checking that a method is called on an object (should_receive), you''d write that assertion before you perform any action. For example: an_object.should_receive(:a_method_call) an_object.a_method_call would pass but an_object.a_method_call an_object.should_receive(:a_method_call) would fail 2. Usually, you make a request in controller specs, like "get :render_404". See the controller docs on the rspec site. Hope that helps, Scott
David Chelimsky
2008-Sep-06 08:41 UTC
[rspec-users] issue with application controller spec
On Fri, Sep 5, 2008 at 10:48 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: > >> I''m having some trouble trying to spec some methods in my Rails >> application controller. >> >> I''m new to rspec converting over from straight test::unit. >> >> Here is the method in my application.rb controller that I''m trying to spec >> >> def render_403 >> logger.debug "Returned 403: #{request.request_uri}" >> render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' >> end >> >> >> Here is my *current* spec >> >> >> describe "handling render 403" do >> >> before(:each) do >> controller.request.should_receive(:request_uri).and_return(''response >> request_uri'') >> end > > First off - should_receive *is* a test - why would you write a test in the > setup? > >> >> it "should render the 403 error page" do >> controller.render_403 >> response.should render_file("#{RAILS_ROOT}/public/403.html") >> end > > Two issues with this test: > > 1. Normally, if you are going to write a test checking that a method is > called on an object (should_receive), you''d write that assertion before you > perform any action. For example: > > an_object.should_receive(:a_method_call) > an_object.a_method_call > > would pass > > but > > an_object.a_method_call > an_object.should_receive(:a_method_call) > > would fail"should render_file" is not a mock expectation, it''s a post-action, more state-based expectation, so Craig''s got this bit right in this case.> 2. Usually, you make a request in controller specs, like "get :render_404". > See the controller docs on the rspec site.I think this is the crux of the problem. Craig, you''d probably learn a lot by running these code examples with the -b flag to get a full backtrace.> Hope that helps,It does :) HTH too, David> > Scott > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Craig Jolicoeur
2008-Sep-06 13:55 UTC
[rspec-users] issue with application controller spec
>>First off - should_receive *is* a test - why would you write a test inthe setup? Not sure what you mean by that. I''m not writing a test in the setup routine. Also, I''m not setting an expectation on a method call. should render_file is in the right place. On Sep 5, 11:48?pm, Scott Taylor <mailing_li... at railsnewbie.com> wrote:> On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: > > > > > I''m having some trouble trying to spec some methods in my Rails ? > > application controller. > > > I''m new to rspec converting over from straight test::unit. > > > Here is the method in my application.rb controller that I''m trying ? > > to spec > > > ?def render_403 > > ? ?logger.debug "Returned 403: #{request.request_uri}" > > ? ?render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' > > ?end > > > Here is my *current* spec > > > ?describe "handling render 403" do > > > ? ?before(:each) do > > > controller.request.should_receive(:request_uri).and_return(''response ? > > request_uri'') > > ? ?end > > First off - should_receive *is* a test - why would you write a test in ? > the setup? > > > > > ? ?it "should render the 403 error page" do > > ? ? ?controller.render_403 > > ? ? ?response.should render_file("#{RAILS_ROOT}/public/403.html") > > ? ?end > > Two issues with this test: > > 1. ?Normally, if you are going to write a test checking that a method ? > is called on an object (should_receive), you''d write that assertion ? > before you perform any action. ?For example: > > an_object.should_receive(:a_method_call) > an_object.a_method_call > > would pass > > but > > an_object.a_method_call > an_object.should_receive(:a_method_call) > > would fail > > 2. Usually, you make a request in controller specs, like ? > "get :render_404". ?See the controller docs on the rspec site. > > Hope that helps, > > Scott > > _______________________________________________ > rspec-users mailing list > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
Craig Jolicoeur
2008-Sep-06 14:15 UTC
[rspec-users] issue with application controller spec
Thanks David. I changed to using get :render_403 and it worked. Well, worked after I added in those routes to my routes.rb file. I dont have the default routes for /:controller/:action/:id so it was failing and I dont want custom routes for these two methods because they will be called from other controllers directly and don''t need a named route. What is the proper way to test application controller methods that get called from other controllers? I will never manually go to / application/render_403 but it seems I had to pretend this would happen to spec it out properly. - Craig On Sep 6, 9:55?am, Craig Jolicoeur <cpjolico... at gmail.com> wrote:> >>First off - should_receive *is* a test - why would you write a test in > > the setup? > > Not sure what you mean by that. ?I''m not writing a test in the setup > routine. > > Also, I''m not setting an expectation on a method call. ?should > render_file is in the right place. > > On Sep 5, 11:48?pm, Scott Taylor <mailing_li... at railsnewbie.com> > wrote: > > > On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: > > > > I''m having some trouble trying to spec some methods in my Rails ? > > > application controller. > > > > I''m new to rspec converting over from straight test::unit. > > > > Here is the method in my application.rb controller that I''m trying ? > > > to spec > > > > ?def render_403 > > > ? ?logger.debug "Returned 403: #{request.request_uri}" > > > ? ?render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' > > > ?end > > > > Here is my *current* spec > > > > ?describe "handling render 403" do > > > > ? ?before(:each) do > > > > controller.request.should_receive(:request_uri).and_return(''response ? > > > request_uri'') > > > ? ?end > > > First off - should_receive *is* a test - why would you write a test in ? > > the setup? > > > > ? ?it "should render the 403 error page" do > > > ? ? ?controller.render_403 > > > ? ? ?response.should render_file("#{RAILS_ROOT}/public/403.html") > > > ? ?end > > > Two issues with this test: > > > 1. ?Normally, if you are going to write a test checking that a method ? > > is called on an object (should_receive), you''d write that assertion ? > > before you perform any action. ?For example: > > > an_object.should_receive(:a_method_call) > > an_object.a_method_call > > > would pass > > > but > > > an_object.a_method_call > > an_object.should_receive(:a_method_call) > > > would fail > > > 2. Usually, you make a request in controller specs, like ? > > "get :render_404". ?See the controller docs on the rspec site. > > > Hope that helps, > > > Scott > > > _______________________________________________ > > rspec-users mailing list > > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
David Chelimsky
2008-Sep-06 14:51 UTC
[rspec-users] issue with application controller spec
On Sat, Sep 6, 2008 at 8:55 AM, Craig Jolicoeur <cpjolicoeur at gmail.com> wrote:>>>First off - should_receive *is* a test - why would you write a test in > the setup? > > Not sure what you mean by that. I''m not writing a test in the setup > routine.should_receive is an expectation which could pass or fail. I think that''s what Scott meant by writing a test in setup (before(:each)). It''s something you generally want to avoid because it makes it more difficult to understand failures if they''re not right in the actual code examples.> Also, I''m not setting an expectation on a method call. should > render_file is in the right place.You''re not *now*, but you could.> > On Sep 5, 11:48 pm, Scott Taylor <mailing_li... at railsnewbie.com> > wrote: >> On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: >> >> >> >> > I''m having some trouble trying to spec some methods in my Rails >> > application controller. >> >> > I''m new to rspec converting over from straight test::unit. >> >> > Here is the method in my application.rb controller that I''m trying >> > to spec >> >> > def render_403 >> > logger.debug "Returned 403: #{request.request_uri}" >> > render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' >> > end >> >> > Here is my *current* spec >> >> > describe "handling render 403" do >> >> > before(:each) do >> >> > controller.request.should_receive(:request_uri).and_return(''response >> > request_uri'') >> > end >> >> First off - should_receive *is* a test - why would you write a test in >> the setup? >> >> >> >> > it "should render the 403 error page" do >> > controller.render_403 >> > response.should render_file("#{RAILS_ROOT}/public/403.html") >> > end >> >> Two issues with this test: >> >> 1. Normally, if you are going to write a test checking that a method >> is called on an object (should_receive), you''d write that assertion >> before you perform any action. For example: >> >> an_object.should_receive(:a_method_call) >> an_object.a_method_call >> >> would pass >> >> but >> >> an_object.a_method_call >> an_object.should_receive(:a_method_call) >> >> would fail >> >> 2. Usually, you make a request in controller specs, like >> "get :render_404". See the controller docs on the rspec site. >> >> Hope that helps, >> >> Scott >> >> _______________________________________________ >> rspec-users mailing list >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
David Chelimsky
2008-Sep-06 15:00 UTC
[rspec-users] issue with application controller spec
On Sat, Sep 6, 2008 at 9:15 AM, Craig Jolicoeur <cpjolicoeur at gmail.com> wrote:> Thanks David. > > I changed to using get :render_403 and it worked. Well, worked after > I added in those routes to my routes.rb file. > > I dont have the default routes for /:controller/:action/:id so it was > failing and I dont want custom routes for these two methods because > they will be called from other controllers directly and don''t need a > named route. > > What is the proper way to test application controller methods that get > called from other controllers?The problem to solve here is the fact that Rails is providing a bunch of setup for us when we go through an action, and the render method in the controller relies on that setup. There are (at least) two ways you could go here, neither of which is perfect, but perhaps you''ll like them better than what you''re doing. One would be to set a message expectation on render: controller.should_receive(:render).with(:file => "#{RAILS_ROOT}/public/403.html", :status => ''403'') controller.get_403 That''s a very implementation specific approach, and this is the sort of thing that leads to endless debate over the costs/benefits of mocking/stubbing. In this particular case, though, it''ll get you the answer you''re looking for. Another approach is to create a fake controller: class FakeController < ApplicationController def action_that_raises_a_403 get_403 end end and add routing for this controller only if ENV[''RAILS_ENV''] == ''test'' (in spec_helper or somewhere in the spec directory). For that matter, you could just add routing for get_403 directly, but because it itself is not really an action, but a helper, it might be more clear to not call it directly, but only from an action. HTH, David> I will never manually go to / > application/render_403 but it seems I had to pretend this would happen > to spec it out properly. > > - Craig > > On Sep 6, 9:55 am, Craig Jolicoeur <cpjolico... at gmail.com> wrote: >> >>First off - should_receive *is* a test - why would you write a test in >> >> the setup? >> >> Not sure what you mean by that. I''m not writing a test in the setup >> routine. >> >> Also, I''m not setting an expectation on a method call. should >> render_file is in the right place. >> >> On Sep 5, 11:48 pm, Scott Taylor <mailing_li... at railsnewbie.com> >> wrote: >> >> > On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: >> >> > > I''m having some trouble trying to spec some methods in my Rails >> > > application controller. >> >> > > I''m new to rspec converting over from straight test::unit. >> >> > > Here is the method in my application.rb controller that I''m trying >> > > to spec >> >> > > def render_403 >> > > logger.debug "Returned 403: #{request.request_uri}" >> > > render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' >> > > end >> >> > > Here is my *current* spec >> >> > > describe "handling render 403" do >> >> > > before(:each) do >> >> > > controller.request.should_receive(:request_uri).and_return(''response >> > > request_uri'') >> > > end >> >> > First off - should_receive *is* a test - why would you write a test in >> > the setup? >> >> > > it "should render the 403 error page" do >> > > controller.render_403 >> > > response.should render_file("#{RAILS_ROOT}/public/403.html") >> > > end >> >> > Two issues with this test: >> >> > 1. Normally, if you are going to write a test checking that a method >> > is called on an object (should_receive), you''d write that assertion >> > before you perform any action. For example: >> >> > an_object.should_receive(:a_method_call) >> > an_object.a_method_call >> >> > would pass >> >> > but >> >> > an_object.a_method_call >> > an_object.should_receive(:a_method_call) >> >> > would fail >> >> > 2. Usually, you make a request in controller specs, like >> > "get :render_404". See the controller docs on the rspec site. >> >> > Hope that helps, >> >> > Scott >> >> > _______________________________________________ >> > rspec-users mailing list >> > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users >> >> _______________________________________________ >> rspec-users mailing list >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Craig Jolicoeur
2008-Sep-06 19:30 UTC
[rspec-users] issue with application controller spec
I think part of my problem, now that I think about it, is that I''m trying to test the method instead of testing behavior. This render_403 method should probably not be tested directly from the application_controller_spec since it doesnt get actually called their. I should test the render method from the controllers where the behavior is actually expected since it makes more sense. Thanks for all the help On Sep 6, 11:00?am, "David Chelimsky" <dchelim... at gmail.com> wrote:> On Sat, Sep 6, 2008 at 9:15 AM, Craig Jolicoeur <cpjolico... at gmail.com> wrote: > > Thanks David. > > > I changed to using get :render_403 and it worked. ?Well, worked after > > I added in those routes to my routes.rb file. > > > I dont have the default routes for /:controller/:action/:id so it was > > failing and I dont want custom routes for these two methods because > > they will be called from other controllers directly and don''t need a > > named route. > > > What is the proper way to test application controller methods that get > > called from other controllers? > > The problem to solve here is the fact that Rails is providing a bunch > of setup for us when we go through an action, and the render method in > the controller relies on that setup. > > There are (at least) two ways you could go here, neither of which is > perfect, but perhaps you''ll like them better than what you''re doing. > > One would be to set a message expectation on render: > > controller.should_receive(:render).with(:file => > "#{RAILS_ROOT}/public/403.html", :status => ''403'') > controller.get_403 > > That''s a very implementation specific approach, and this is the sort > of thing that leads to endless debate over the costs/benefits of > mocking/stubbing. In this particular case, though, it''ll get you the > answer you''re looking for. > > Another approach is to create a fake controller: > > class FakeController < ApplicationController > ? def action_that_raises_a_403 > ? ? get_403 > ? end > end > > and add routing for this controller only if ENV[''RAILS_ENV''] == ''test'' > (in spec_helper or somewhere in the spec directory). > > For that matter, you could just add routing for get_403 directly, but > because it itself is not really an action, but a helper, it might be > more clear to not call it directly, but only from an action. > > HTH, > David > > > > > I will never manually go to / > > application/render_403 but it seems I had to pretend this would happen > > to spec it out properly. > > > - Craig > > > On Sep 6, 9:55 am, Craig Jolicoeur <cpjolico... at gmail.com> wrote: > >> >>First off - should_receive *is* a test - why would you write a test in > > >> the setup? > > >> Not sure what you mean by that. ?I''m not writing a test in the setup > >> routine. > > >> Also, I''m not setting an expectation on a method call. ?should > >> render_file is in the right place. > > >> On Sep 5, 11:48 pm, Scott Taylor <mailing_li... at railsnewbie.com> > >> wrote: > > >> > On Sep 5, 2008, at 10:18 PM, Craig P Jolicoeur wrote: > > >> > > I''m having some trouble trying to spec some methods in my Rails > >> > > application controller. > > >> > > I''m new to rspec converting over from straight test::unit. > > >> > > Here is the method in my application.rb controller that I''m trying > >> > > to spec > > >> > > ?def render_403 > >> > > ? ?logger.debug "Returned 403: #{request.request_uri}" > >> > > ? ?render :file => "#{RAILS_ROOT}/public/403.html", :status => ''403'' > >> > > ?end > > >> > > Here is my *current* spec > > >> > > ?describe "handling render 403" do > > >> > > ? ?before(:each) do > > >> > > controller.request.should_receive(:request_uri).and_return(''response > >> > > request_uri'') > >> > > ? ?end > > >> > First off - should_receive *is* a test - why would you write a test in > >> > the setup? > > >> > > ? ?it "should render the 403 error page" do > >> > > ? ? ?controller.render_403 > >> > > ? ? ?response.should render_file("#{RAILS_ROOT}/public/403.html") > >> > > ? ?end > > >> > Two issues with this test: > > >> > 1. ?Normally, if you are going to write a test checking that a method > >> > is called on an object (should_receive), you''d write that assertion > >> > before you perform any action. ?For example: > > >> > an_object.should_receive(:a_method_call) > >> > an_object.a_method_call > > >> > would pass > > >> > but > > >> > an_object.a_method_call > >> > an_object.should_receive(:a_method_call) > > >> > would fail > > >> > 2. Usually, you make a request in controller specs, like > >> > "get :render_404". ?See the controller docs on the rspec site. > > >> > Hope that helps, > > >> > Scott > > >> > _______________________________________________ > >> > rspec-users mailing list > >> > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > > >> _______________________________________________ > >> rspec-users mailing list > >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > > rspec-users mailing list > > rspec-us... at rubyforge.org > >http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users