Timo Rößner
2010-Jul-26 16:12 UTC
[rspec-users] render_template expectation - surprising pattern matching issue
Hey guys, we just found out by accident that rspec seems to apply a pretty confusing mechanism to ensure that a certain template is rendered. To clarify, consider this standard controller spec: # working it ''GET edit'' do get :edit, :id => ''37'' response.should render_template(:edit) end So far, so good. Now to the surprising part: # NOT working it ''GET edit'' do get :edit, :id => ''37'' response.should render_template(:eda) end # -> here''s the surprise: working it ''GET edit'' do get :edit, :id => ''37'' response.should render_template(:edi) end Apparently rspec uses a pretty generous pattern matching to ensure that a certain template is rendered. If I had to guess, I''d say that''s because rspec wants to ignore path / namespacing / different file endings (html.haml, html.erb and so on). I still think this approach is suboptimal for two reasons: 1.) It violates the principle of least suprise, this behaviour is more like "the biggest surprise possible" - who would have thought that example nr.3 is working? 2.) I can easily imagine a situation where 2 or more actions start with the same letters. In this case, what would happen if you changed the "render_template"-call (i.e. shortening the template name) and remove one action. Wouldnt the specs still be green although one view would be completely missing? 2 questions: 1.) Is this a bug or a feature? 2.) Why not change the pattern matching that it still ignores paths and file endings, but at least tries to match the expected template exactly to the rendered template?
Phillip Koebbe
2010-Jul-26 16:22 UTC
[rspec-users] render_template expectation - surprising pattern matching issue
On 2010-07-26 11:12 AM, Timo R??ner wrote:> Hey guys, > > we just found out by accident that rspec seems to apply a pretty > confusing mechanism to ensure that a certain template is rendered. > > To clarify, consider this standard controller spec: > > # working > it ''GET edit'' do > get :edit, :id => ''37'' > response.should render_template(:edit) > end > > So far, so good. Now to the surprising part: > > # NOT working > it ''GET edit'' do > get :edit, :id => ''37'' > response.should render_template(:eda) > end > > # -> here''s the surprise: working > it ''GET edit'' do > get :edit, :id => ''37'' > response.should render_template(:edi) > end > > Apparently rspec uses a pretty generous pattern matching to ensure > that a certain template is rendered. > > If I had to guess, I''d say that''s because rspec wants to ignore path / > namespacing / different file endings (html.haml, html.erb and so on). > > I still think this approach is suboptimal for two reasons: > > 1.) It violates the principle of least suprise, this behaviour is more > like "the biggest surprise possible" - who would have thought that > example nr.3 is working? > > 2.) I can easily imagine a situation where 2 or more actions start > with the same letters. In this case, what would happen if you changed > the "render_template"-call (i.e. shortening the template name) and > remove one action. > Wouldnt the specs still be green although one view would be completely > missing? > > 2 questions: > > 1.) Is this a bug or a feature? > > 2.) Why not change the pattern matching that it still ignores paths > and file endings, but at least tries to match the expected template > exactly to the rendered template? > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-usersI''ve experienced a bit of pain with making sure the right view gets rendered. Initially, I was doing essentially what you are doing, but noticed that the specs would pass even if I didn''t render the view (ie, the view wasn''t there). Then I discovered integrate_views, which helped immensely in that regard, until I later discovered that I had to mock and stub everything that the view expected. Hated that. I''ve since started using something that is not quite as unobtrusive as I''d like, but I much prefer the results. I don''t integrate_views any more and I set an expectation on the controller to render. Something like: describe ''get :index'' do it ''should render the index view'' do controller.should_receive(:render).with(:index) get :index end end The unfortunate part of this is that I must then explicitly render the view in the controller action: def index ... render :index end I wish I didn''t have to do it that way, but so far, this is the best I can do to balance specing the controller with keeping things isolated. I openly admit there might be a better solution and I may very well have overlooked something obvious. I didn''t spend a lot of time trying to get this figured out correctly, so there may be a better way. Peace, Phillip