Andrew Selder
2008-Jun-16 19:58 UTC
[rspec-users] render_to_string confusing ControllerSpec
Hi all, I have a controller I''m trying to spec out, and I''m running into some issues with render_to_string. Basically, the show gets an array of objects, calls render_to_string for each of them, and then renders the show template. So I have the standard spec: it "should render show template" do do_get response.should render_template(''show'') end but when I run the spec I get the following failure: ''SearchesController handling GET /searches/1 should render show template'' FAILED expected "show", got "properties/_map_info_box" Does anybody have any ideas? Thanks, Andrew
David Chelimsky
2008-Jun-17 01:34 UTC
[rspec-users] render_to_string confusing ControllerSpec
On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote:> Hi all, > > I have a controller I''m trying to spec out, and I''m running into > some issues with render_to_string. > > Basically, the show gets an array of objects, calls render_to_string > for each of them, and then renders the show template. > > So I have the standard spec: > > > it "should render show template" do > do_get > response.should render_template(''show'') > end > > > but when I run the spec I get the following failure: > > ''SearchesController handling GET /searches/1 should render show > template'' FAILED > expected "show", got "properties/_map_info_box" > > > Does anybody have any ideas?Please post the controller action and the full backtrace: script/spec spec/controller/path/to/the/spec.rb -fsb Thx
Andrew Selder
2008-Jun-17 01:59 UTC
[rspec-users] render_to_string confusing ControllerSpec
Here''s the back trace 1) ''SearchesController handling GET /searches/1 should render show template'' FAILED expected "show", got "properties/_map_info_box" /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ expectations.rb:52:in `fail_with'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ expectations/handler.rb:25:in `handle_matcher'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ expectations/extensions/object.rb:31:in `should'' ./spec/controllers/searches_controller_spec.rb:26: /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_methods.rb:84:in `instance_eval'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_methods.rb:84:in `run_with_description_capturing'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_methods.rb:21:in `execute'' /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_methods.rb:18:in `execute'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_group_methods.rb:303:in `execute_examples'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_group_methods.rb:302:in `each'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_group_methods.rb:302:in `execute_examples'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ example/example_group_methods.rb:130:in `run'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ runner/example_group_runner.rb:22:in `run'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ runner/example_group_runner.rb:21:in `each'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ runner/example_group_runner.rb:21:in `run'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ runner/options.rb:106:in `run_examples'' /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ runner/command_line.rb:19:in `run'' script/spec:4: And here''s the controller action: def show @search = Search.find(params[:id]) if @search.too_many_results? message_to_new "Your search returned too many results (#{@search.count }). Please narrow your criteria and search again." return elsif @search.no_results? message_to_new "Your search returned no results. Please change your criteria and search again." return end init_map @props = @search.do_search @markers = [] @props.each do |prop| coords = prop.latlng unless coords.lat == 0 || coords.lng == 0 prop.info_box = render_to_string(:partial => "/properties/ map_info_box", :object => prop) mark = prop.has_photos? ? "green" : "red" marker = GMarker.new(coords, :title => prop_help.bubble_header(prop), :info_window => prop.info_box, :icon => Variable.new(mark)) @map.overlay_init marker @markers << marker end end unless @markers.empty? @map.center_zoom_on_points_init(*(@markers.collect {|x| x.point})) else @map.center_zoom_init(@search.center, 12) end end Thanks, Andrew On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote:> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: > >> Hi all, >> >> I have a controller I''m trying to spec out, and I''m running into >> some issues with render_to_string. >> >> Basically, the show gets an array of objects, calls >> render_to_string for each of them, and then renders the show >> template. >> >> So I have the standard spec: >> >> >> it "should render show template" do >> do_get >> response.should render_template(''show'') >> end >> >> >> but when I run the spec I get the following failure: >> >> ''SearchesController handling GET /searches/1 should render show >> template'' FAILED >> expected "show", got "properties/_map_info_box" >> >> >> Does anybody have any ideas? > > Please post the controller action and the full backtrace: > > script/spec spec/controller/path/to/the/spec.rb -fsb > > Thx > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
David Chelimsky
2008-Jun-17 02:03 UTC
[rspec-users] render_to_string confusing ControllerSpec
On Jun 16, 2008, at 8:59 PM, Andrew Selder wrote:> Here''s the back trace > > 1) > ''SearchesController handling GET /searches/1 should render show > template'' FAILED > expected "show", got "properties/_map_info_box" > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > expectations.rb:52:in `fail_with'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > expectations/handler.rb:25:in `handle_matcher'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > expectations/extensions/object.rb:31:in `should'' > ./spec/controllers/searches_controller_spec.rb:26: > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_methods.rb:84:in `instance_eval'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_methods.rb:84:in `run_with_description_capturing'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_methods.rb:21:in `execute'' > /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_methods.rb:18:in `execute'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_group_methods.rb:303:in `execute_examples'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_group_methods.rb:302:in `each'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_group_methods.rb:302:in `execute_examples'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > example/example_group_methods.rb:130:in `run'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > runner/example_group_runner.rb:22:in `run'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > runner/example_group_runner.rb:21:in `each'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > runner/example_group_runner.rb:21:in `run'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > runner/options.rb:106:in `run_examples'' > /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ > runner/command_line.rb:19:in `run'' > script/spec:4: > > And here''s the controller action: > > def show > @search = Search.find(params[:id]) > if @search.too_many_results? > message_to_new "Your search returned too many results (#{@search.count > }). Please narrow your criteria and search again." > return > elsif @search.no_results? > message_to_new "Your search returned no results. Please change > your criteria and search again." > return > end > init_map > @props = @search.do_search > @markers = [] > @props.each do |prop| > coords = prop.latlng > unless coords.lat == 0 || coords.lng == 0 > prop.info_box = render_to_string(:partial => "/properties/ > map_info_box", :object => prop)This is the line that''s causing you trouble. Try stubbing this one out as well: response.stub_render(:partial => "/properties/map_info_box", :object => anything()) Let us know if it works. Cheers, David> > mark = prop.has_photos? ? "green" : "red" > marker = GMarker.new(coords, :title => > prop_help.bubble_header(prop), :info_window => prop.info_box, :icon > => Variable.new(mark)) > @map.overlay_init marker > @markers << marker > end > end > unless @markers.empty? > @map.center_zoom_on_points_init(*(@markers.collect {|x| > x.point})) > else > @map.center_zoom_init(@search.center, 12) > end > end > > Thanks, > > Andrew > > On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote: > >> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: >> >>> Hi all, >>> >>> I have a controller I''m trying to spec out, and I''m running into >>> some issues with render_to_string. >>> >>> Basically, the show gets an array of objects, calls >>> render_to_string for each of them, and then renders the show >>> template. >>> >>> So I have the standard spec: >>> >>> >>> it "should render show template" do >>> do_get >>> response.should render_template(''show'') >>> end >>> >>> >>> but when I run the spec I get the following failure: >>> >>> ''SearchesController handling GET /searches/1 should render show >>> template'' FAILED >>> expected "show", got "properties/_map_info_box" >>> >>> >>> Does anybody have any ideas? >> >> Please post the controller action and the full backtrace: >> >> script/spec spec/controller/path/to/the/spec.rb -fsb >> >> Thx >> _______________________________________________ >> 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
Andrew Selder
2008-Jun-17 02:19 UTC
[rspec-users] render_to_string confusing ControllerSpec
I updated the spec to look like this: it "should render show template" do do_get controller.stub_render(:partial => "/properties/ map_info_box", :object => anything()) response.should render_template(''show'') end and I still get the same failure and back trace. In addition to not working, the problem with stubbing out that render to string is that I can''t then check for the presence of those strings in the final output. Thanks, Andrew On Jun 16, 2008, at 10:03 PM, David Chelimsky wrote:> On Jun 16, 2008, at 8:59 PM, Andrew Selder wrote: > >> Here''s the back trace >> >> 1) >> ''SearchesController handling GET /searches/1 should render show >> template'' FAILED >> expected "show", got "properties/_map_info_box" >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> expectations.rb:52:in `fail_with'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> expectations/handler.rb:25:in `handle_matcher'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> expectations/extensions/object.rb:31:in `should'' >> ./spec/controllers/searches_controller_spec.rb:26: >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_methods.rb:84:in `instance_eval'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_methods.rb:84:in `run_with_description_capturing'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_methods.rb:21:in `execute'' >> /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_methods.rb:18:in `execute'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_group_methods.rb:303:in `execute_examples'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_group_methods.rb:302:in `each'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_group_methods.rb:302:in `execute_examples'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> example/example_group_methods.rb:130:in `run'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> runner/example_group_runner.rb:22:in `run'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> runner/example_group_runner.rb:21:in `each'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> runner/example_group_runner.rb:21:in `run'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> runner/options.rb:106:in `run_examples'' >> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/ >> runner/command_line.rb:19:in `run'' >> script/spec:4: >> >> And here''s the controller action: >> >> def show >> @search = Search.find(params[:id]) >> if @search.too_many_results? >> message_to_new "Your search returned too many results (#{@search.count >> }). Please narrow your criteria and search again." >> return >> elsif @search.no_results? >> message_to_new "Your search returned no results. Please change >> your criteria and search again." >> return >> end >> init_map >> @props = @search.do_search >> @markers = [] >> @props.each do |prop| >> coords = prop.latlng >> unless coords.lat == 0 || coords.lng == 0 >> prop.info_box = render_to_string(:partial => "/properties/ >> map_info_box", :object => prop) > > This is the line that''s causing you trouble. Try stubbing this one > out as well: > > response.stub_render(:partial => "/properties/map_info_box", :object > => anything()) > > Let us know if it works. > > Cheers, > David > >> >> mark = prop.has_photos? ? "green" : "red" >> marker = GMarker.new(coords, :title => >> prop_help.bubble_header(prop), :info_window => prop.info_box, :icon >> => Variable.new(mark)) >> @map.overlay_init marker >> @markers << marker >> end >> end >> unless @markers.empty? >> @map.center_zoom_on_points_init(*(@markers.collect {|x| >> x.point})) >> else >> @map.center_zoom_init(@search.center, 12) >> end >> end >> >> Thanks, >> >> Andrew >> >> On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote: >> >>> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: >>> >>>> Hi all, >>>> >>>> I have a controller I''m trying to spec out, and I''m running into >>>> some issues with render_to_string. >>>> >>>> Basically, the show gets an array of objects, calls >>>> render_to_string for each of them, and then renders the show >>>> template. >>>> >>>> So I have the standard spec: >>>> >>>> >>>> it "should render show template" do >>>> do_get >>>> response.should render_template(''show'') >>>> end >>>> >>>> >>>> but when I run the spec I get the following failure: >>>> >>>> ''SearchesController handling GET /searches/1 should render show >>>> template'' FAILED >>>> expected "show", got "properties/_map_info_box" >>>> >>>> >>>> Does anybody have any ideas? >>> >>> Please post the controller action and the full backtrace: >>> >>> script/spec spec/controller/path/to/the/spec.rb -fsb >>> >>> Thx >>> _______________________________________________ >>> 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 > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
David Chelimsky
2008-Jun-17 03:05 UTC
[rspec-users] render_to_string confusing ControllerSpec
On Jun 16, 2008, at 9:19 PM, Andrew Selder wrote:> I updated the spec to look like this: > > it "should render show template" do > do_get > controller.stub_render(:partial => "/properties/ > map_info_box", :object => anything()) > response.should render_template(''show'') > end > > and I still get the same failure and back trace. > > In addition to not working, the problem with stubbing out that > render to string is that I can''t then check for the presence of > those strings in the final output.Well, therein lies the real problem :) This action is exhibiting a number of code smells. I don''t know how familiar you might be w/ that, but: Long Method - a method that does too many things (I count at least 10) Feature Envy - one one object is doing work on another object''s data There''s also a lot of asking, violating the Tell Don''t Ask principle. This block: @props.each do |prop| coords = prop.latlng unless coords.lat == 0 || coords.lng == 0 prop.info_box = render_to_string(:partial => "/properties/ map_info_box", :object => prop) mark = prop.has_photos? ? "green" : "red" marker = GMarker.new(coords, :title => prop_help.bubble_header(prop),\ :info_window => prop.info_box, :icon => Variable.new(mark)) @map.overlay_init marker @markers << marker end end .. could become: @props.each do |prop| @markers << prop.generate_marker if prop.needs_marker? end Much simpler to test at that point! I''d recommend heading down that path. HTH, David> Thanks, > > Andrew > > On Jun 16, 2008, at 10:03 PM, David Chelimsky wrote: > >> On Jun 16, 2008, at 8:59 PM, Andrew Selder wrote: >> >>> Here''s the back trace >>> >>> 1) >>> ''SearchesController handling GET /searches/1 should render show >>> template'' FAILED >>> expected "show", got "properties/_map_info_box" >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/expectations.rb:52:in `fail_with'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/expectations/handler.rb:25:in `handle_matcher'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/expectations/extensions/object.rb:31:in `should'' >>> ./spec/controllers/searches_controller_spec.rb:26: >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_methods.rb:84:in `instance_eval'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_methods.rb:84:in >>> `run_with_description_capturing'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_methods.rb:21:in `execute'' >>> /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_methods.rb:18:in `execute'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_group_methods.rb:303:in `execute_examples'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_group_methods.rb:302:in `each'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_group_methods.rb:302:in `execute_examples'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/example/example_group_methods.rb:130:in `run'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/runner/example_group_runner.rb:22:in `run'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/runner/example_group_runner.rb:21:in `each'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/runner/example_group_runner.rb:21:in `run'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/runner/options.rb:106:in `run_examples'' >>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>> spec/runner/command_line.rb:19:in `run'' >>> script/spec:4: >>> >>> And here''s the controller action: >>> >>> def show >>> @search = Search.find(params[:id]) >>> if @search.too_many_results? >>> message_to_new "Your search returned too many results (#{@search.count >>> }). Please narrow your criteria and search again." >>> return >>> elsif @search.no_results? >>> message_to_new "Your search returned no results. Please change >>> your criteria and search again." >>> return >>> end >>> init_map >>> @props = @search.do_search >>> @markers = [] >>> @props.each do |prop| >>> coords = prop.latlng >>> unless coords.lat == 0 || coords.lng == 0 >>> prop.info_box = render_to_string(:partial => "/properties/ >>> map_info_box", :object => prop) >> >> This is the line that''s causing you trouble. Try stubbing this one >> out as well: >> >> response.stub_render(:partial => "/properties/ >> map_info_box", :object => anything()) >> >> Let us know if it works. >> >> Cheers, >> David >> >>> >>> mark = prop.has_photos? ? "green" : "red" >>> marker = GMarker.new(coords, :title => >>> prop_help.bubble_header(prop), :info_window => >>> prop.info_box, :icon => Variable.new(mark)) >>> @map.overlay_init marker >>> @markers << marker >>> end >>> end >>> unless @markers.empty? >>> @map.center_zoom_on_points_init(*(@markers.collect {|x| >>> x.point})) >>> else >>> @map.center_zoom_init(@search.center, 12) >>> end >>> end >>> >>> Thanks, >>> >>> Andrew >>> >>> On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote: >>> >>>> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: >>>> >>>>> Hi all, >>>>> >>>>> I have a controller I''m trying to spec out, and I''m running into >>>>> some issues with render_to_string. >>>>> >>>>> Basically, the show gets an array of objects, calls >>>>> render_to_string for each of them, and then renders the show >>>>> template. >>>>> >>>>> So I have the standard spec: >>>>> >>>>> >>>>> it "should render show template" do >>>>> do_get >>>>> response.should render_template(''show'') >>>>> end >>>>> >>>>> >>>>> but when I run the spec I get the following failure: >>>>> >>>>> ''SearchesController handling GET /searches/1 should render show >>>>> template'' FAILED >>>>> expected "show", got "properties/_map_info_box" >>>>> >>>>> >>>>> Does anybody have any ideas? >>>> >>>> Please post the controller action and the full backtrace: >>>> >>>> script/spec spec/controller/path/to/the/spec.rb -fsb >>>> >>>> Thx >>>> _______________________________________________ >>>> 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 >> >> _______________________________________________ >> 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
Andrew Selder
2008-Jun-17 03:23 UTC
[rspec-users] render_to_string confusing ControllerSpec
David, Valid point about the method needing some refactoring. But another key rule of refactoring is to have passing tests before refactoring. This is one of the things that''s a minor annoyance I have about rails, you can''t associate views with models. The problem with the refactoring suggested is that render_to_string is a member of ActionController::Base, and moving it in to a string construction method in the model is complicated by no helpers available in the model, and that partial uses tons of helpers. So it''s hard to move a generate_marker method to the model. Regardless of all of the above, RSpec controller specs have issues when testing which template was rendered if you use render_to_string. Andrew On Jun 16, 2008, at 11:05 PM, David Chelimsky wrote:> On Jun 16, 2008, at 9:19 PM, Andrew Selder wrote: > >> I updated the spec to look like this: >> >> it "should render show template" do >> do_get >> controller.stub_render(:partial => "/properties/ >> map_info_box", :object => anything()) >> response.should render_template(''show'') >> end >> >> and I still get the same failure and back trace. >> >> In addition to not working, the problem with stubbing out that >> render to string is that I can''t then check for the presence of >> those strings in the final output. > > Well, therein lies the real problem :) This action is exhibiting a > number of code smells. I don''t know how familiar you might be w/ > that, but: > > Long Method - a method that does too many things (I count at least > 10) > Feature Envy - one one object is doing work on another object''s data > > There''s also a lot of asking, violating the Tell Don''t Ask principle. > > This block: > > @props.each do |prop| > coords = prop.latlng > unless coords.lat == 0 || coords.lng == 0 > prop.info_box = render_to_string(:partial => "/properties/ > map_info_box", :object => prop) > mark = prop.has_photos? ? "green" : "red" > marker = GMarker.new(coords, :title => > prop_help.bubble_header(prop),\ > :info_window => prop.info_box, :icon => Variable.new(mark)) > @map.overlay_init marker > @markers << marker > end > end > > .. could become: > > @props.each do |prop| > @markers << prop.generate_marker if prop.needs_marker? > end > > Much simpler to test at that point! I''d recommend heading down that > path. > > HTH, > David > > > >> Thanks, >> >> Andrew >> >> On Jun 16, 2008, at 10:03 PM, David Chelimsky wrote: >> >>> On Jun 16, 2008, at 8:59 PM, Andrew Selder wrote: >>> >>>> Here''s the back trace >>>> >>>> 1) >>>> ''SearchesController handling GET /searches/1 should render show >>>> template'' FAILED >>>> expected "show", got "properties/_map_info_box" >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/expectations.rb:52:in `fail_with'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/expectations/handler.rb:25:in `handle_matcher'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/expectations/extensions/object.rb:31:in `should'' >>>> ./spec/controllers/searches_controller_spec.rb:26: >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_methods.rb:84:in `instance_eval'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_methods.rb:84:in >>>> `run_with_description_capturing'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_methods.rb:21:in `execute'' >>>> /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_methods.rb:18:in `execute'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_group_methods.rb:303:in `execute_examples'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_group_methods.rb:302:in `each'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_group_methods.rb:302:in `execute_examples'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/example/example_group_methods.rb:130:in `run'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/runner/example_group_runner.rb:22:in `run'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/runner/example_group_runner.rb:21:in `each'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/runner/example_group_runner.rb:21:in `run'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/runner/options.rb:106:in `run_examples'' >>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/ >>>> spec/runner/command_line.rb:19:in `run'' >>>> script/spec:4: >>>> >>>> And here''s the controller action: >>>> >>>> def show >>>> @search = Search.find(params[:id]) >>>> if @search.too_many_results? >>>> message_to_new "Your search returned too many results (#{@search.count >>>> }). Please narrow your criteria and search again." >>>> return >>>> elsif @search.no_results? >>>> message_to_new "Your search returned no results. Please change >>>> your criteria and search again." >>>> return >>>> end >>>> init_map >>>> @props = @search.do_search >>>> @markers = [] >>>> @props.each do |prop| >>>> coords = prop.latlng >>>> unless coords.lat == 0 || coords.lng == 0 >>>> prop.info_box = render_to_string(:partial => "/properties/ >>>> map_info_box", :object => prop) >>> >>> This is the line that''s causing you trouble. Try stubbing this one >>> out as well: >>> >>> response.stub_render(:partial => "/properties/ >>> map_info_box", :object => anything()) >>> >>> Let us know if it works. >>> >>> Cheers, >>> David >>> >>>> >>>> mark = prop.has_photos? ? "green" : "red" >>>> marker = GMarker.new(coords, :title => >>>> prop_help.bubble_header(prop), :info_window => >>>> prop.info_box, :icon => Variable.new(mark)) >>>> @map.overlay_init marker >>>> @markers << marker >>>> end >>>> end >>>> unless @markers.empty? >>>> @map.center_zoom_on_points_init(*(@markers.collect {|x| >>>> x.point})) >>>> else >>>> @map.center_zoom_init(@search.center, 12) >>>> end >>>> end >>>> >>>> Thanks, >>>> >>>> Andrew >>>> >>>> On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote: >>>> >>>>> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: >>>>> >>>>>> Hi all, >>>>>> >>>>>> I have a controller I''m trying to spec out, and I''m running >>>>>> into some issues with render_to_string. >>>>>> >>>>>> Basically, the show gets an array of objects, calls >>>>>> render_to_string for each of them, and then renders the show >>>>>> template. >>>>>> >>>>>> So I have the standard spec: >>>>>> >>>>>> >>>>>> it "should render show template" do >>>>>> do_get >>>>>> response.should render_template(''show'') >>>>>> end >>>>>> >>>>>> >>>>>> but when I run the spec I get the following failure: >>>>>> >>>>>> ''SearchesController handling GET /searches/1 should render show >>>>>> template'' FAILED >>>>>> expected "show", got "properties/_map_info_box" >>>>>> >>>>>> >>>>>> Does anybody have any ideas? >>>>> >>>>> Please post the controller action and the full backtrace: >>>>> >>>>> script/spec spec/controller/path/to/the/spec.rb -fsb >>>>> >>>>> Thx >>>>> _______________________________________________ >>>>> 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 >>> >>> _______________________________________________ >>> 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 > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
David Chelimsky
2008-Jun-17 11:14 UTC
[rspec-users] render_to_string confusing ControllerSpec
On Mon, Jun 16, 2008 at 10:23 PM, Andrew Selder <aselder at mac.com> wrote:> David, > > Valid point about the method needing some refactoring. But another key rule > of refactoring is to have passing tests before refactoring.Catch 22 indeed. Are you familiar w/ Michael Feathers'' book Working Effectively with Legacy Code? The working definition of Legacy Code in that book is any code without tests. He''s got a bunch of strategies in there for dealing with situations like this - not in Rails, but the same general concepts and trade-offs apply. Following that book''s advice, you might use integrate_views and create an example that is more like a Rails functional test to start. Maybe even an integration test (using RSpec Stories or Rails Integration Test direction). Then, as you refactor pieces out you can drive that process w/ smaller examples.> This is one of the things that''s a minor annoyance I have about rails, you > can''t associate views with models. The problem with the refactoring > suggested is that render_to_string is a member of ActionController::Base, > and moving it in to a string construction method in the model is complicated > by no helpers available in the model, and that partial uses tons of helpers. > So it''s hard to move a generate_marker method to the model.Got it. I wonder if it would be justifiable in a case like this to create a special object for this purpose then - one that includes all the helpers you need. Just a thought. Unusual to do that sort of thing in Rails, but I used to see and do that sort of thing all the time in other frameworks. Makes things nicely decoupled and easier to test.> Regardless of all of the above, RSpec controller specs have issues when > testing which template was rendered if you use render_to_string.I don''t think this is an RSpec problem at all. We''d have the same problem in any other framework. I''d say it''s a conflict between Rails design choices and the desire to test at this level of granularity. Not saying either is "right." We get a lot of good from both things. But they are sometimes in conflict. I''d try testing this at the higher level (as suggested above) to start. The other thing you might try is mocking render_to_string directly on the controller. controller.should_receive(:render_to_string).with(...).any_number_of_times Or you could stub do_search and return a known set of props to get more specific, but to do that you''re going to end up with a ton of mocks and stubs for this example and without anything higher level to begin with that''s not always the safest bet. But all of this is temporary. I think we can agree that the goal is trim this puppy down somehow, so whatever you do to get there with confidence is OK and throwing out most of that in favor of more granular examples and methods as they emerge is definitely OK. Good luck. Cheers, David> Andrew > > > > On Jun 16, 2008, at 11:05 PM, David Chelimsky wrote: > >> On Jun 16, 2008, at 9:19 PM, Andrew Selder wrote: >> >>> I updated the spec to look like this: >>> >>> it "should render show template" do >>> do_get >>> controller.stub_render(:partial => "/properties/map_info_box", :object >>> => anything()) >>> response.should render_template(''show'') >>> end >>> >>> and I still get the same failure and back trace. >>> >>> In addition to not working, the problem with stubbing out that render to >>> string is that I can''t then check for the presence of those strings in the >>> final output. >> >> Well, therein lies the real problem :) This action is exhibiting a number >> of code smells. I don''t know how familiar you might be w/ that, but: >> >> Long Method - a method that does too many things (I count at least 10) >> Feature Envy - one one object is doing work on another object''s data >> >> There''s also a lot of asking, violating the Tell Don''t Ask principle. >> >> This block: >> >> @props.each do |prop| >> coords = prop.latlng >> unless coords.lat == 0 || coords.lng == 0 >> prop.info_box = render_to_string(:partial => >> "/properties/map_info_box", :object => prop) >> mark = prop.has_photos? ? "green" : "red" >> marker = GMarker.new(coords, :title => prop_help.bubble_header(prop),\ >> :info_window => prop.info_box, :icon => Variable.new(mark)) >> @map.overlay_init marker >> @markers << marker >> end >> end >> >> .. could become: >> >> @props.each do |prop| >> @markers << prop.generate_marker if prop.needs_marker? >> end >> >> Much simpler to test at that point! I''d recommend heading down that path. >> >> HTH, >> David >> >> >> >>> Thanks, >>> >>> Andrew >>> >>> On Jun 16, 2008, at 10:03 PM, David Chelimsky wrote: >>> >>>> On Jun 16, 2008, at 8:59 PM, Andrew Selder wrote: >>>> >>>>> Here''s the back trace >>>>> >>>>> 1) >>>>> ''SearchesController handling GET /searches/1 should render show >>>>> template'' FAILED >>>>> expected "show", got "properties/_map_info_box" >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/expectations.rb:52:in >>>>> `fail_with'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/expectations/handler.rb:25:in >>>>> `handle_matcher'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/expectations/extensions/object.rb:31:in >>>>> `should'' >>>>> ./spec/controllers/searches_controller_spec.rb:26: >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_methods.rb:84:in >>>>> `instance_eval'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_methods.rb:84:in >>>>> `run_with_description_capturing'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_methods.rb:21:in >>>>> `execute'' >>>>> /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_methods.rb:18:in >>>>> `execute'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:303:in >>>>> `execute_examples'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:302:in >>>>> `each'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:302:in >>>>> `execute_examples'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:130:in >>>>> `run'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:22:in >>>>> `run'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in >>>>> `each'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in >>>>> `run'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/runner/options.rb:106:in >>>>> `run_examples'' >>>>> >>>>> /Users/aselder/BostonLogic/one_system/vendor/plugins/rspec/lib/spec/runner/command_line.rb:19:in >>>>> `run'' >>>>> script/spec:4: >>>>> >>>>> And here''s the controller action: >>>>> >>>>> def show >>>>> @search = Search.find(params[:id]) >>>>> if @search.too_many_results? >>>>> message_to_new "Your search returned too many results >>>>> (#{@search.count}). Please narrow your criteria and search again." >>>>> return >>>>> elsif @search.no_results? >>>>> message_to_new "Your search returned no results. Please change your >>>>> criteria and search again." >>>>> return >>>>> end >>>>> init_map >>>>> @props = @search.do_search >>>>> @markers = [] >>>>> @props.each do |prop| >>>>> coords = prop.latlng >>>>> unless coords.lat == 0 || coords.lng == 0 >>>>> prop.info_box = render_to_string(:partial => >>>>> "/properties/map_info_box", :object => prop) >>>> >>>> This is the line that''s causing you trouble. Try stubbing this one out >>>> as well: >>>> >>>> response.stub_render(:partial => "/properties/map_info_box", :object => >>>> anything()) >>>> >>>> Let us know if it works. >>>> >>>> Cheers, >>>> David >>>> >>>>> >>>>> mark = prop.has_photos? ? "green" : "red" >>>>> marker = GMarker.new(coords, :title => >>>>> prop_help.bubble_header(prop), :info_window => prop.info_box, :icon => >>>>> Variable.new(mark)) >>>>> @map.overlay_init marker >>>>> @markers << marker >>>>> end >>>>> end >>>>> unless @markers.empty? >>>>> @map.center_zoom_on_points_init(*(@markers.collect {|x| x.point})) >>>>> else >>>>> @map.center_zoom_init(@search.center, 12) >>>>> end >>>>> end >>>>> >>>>> Thanks, >>>>> >>>>> Andrew >>>>> >>>>> On Jun 16, 2008, at 9:34 PM, David Chelimsky wrote: >>>>> >>>>>> On Jun 16, 2008, at 2:58 PM, Andrew Selder wrote: >>>>>> >>>>>>> Hi all, >>>>>>> >>>>>>> I have a controller I''m trying to spec out, and I''m running into some >>>>>>> issues with render_to_string. >>>>>>> >>>>>>> Basically, the show gets an array of objects, calls render_to_string >>>>>>> for each of them, and then renders the show template. >>>>>>> >>>>>>> So I have the standard spec: >>>>>>> >>>>>>> >>>>>>> it "should render show template" do >>>>>>> do_get >>>>>>> response.should render_template(''show'') >>>>>>> end >>>>>>> >>>>>>> >>>>>>> but when I run the spec I get the following failure: >>>>>>> >>>>>>> ''SearchesController handling GET /searches/1 should render show >>>>>>> template'' FAILED >>>>>>> expected "show", got "properties/_map_info_box" >>>>>>> >>>>>>> >>>>>>> Does anybody have any ideas? >>>>>> >>>>>> Please post the controller action and the full backtrace: >>>>>> >>>>>> script/spec spec/controller/path/to/the/spec.rb -fsb >>>>>> >>>>>> Thx >>>>>> _______________________________________________ >>>>>> 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 >>>> >>>> _______________________________________________ >>>> 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 >> >> _______________________________________________ >> 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 >