tag:www.rhnh.net,2008:/controllersControllers - Xavier Shay's Blog2008-04-19T11:32:53ZEnkiXavier Shaynotreal@rhnh.nettag:www.rhnh.net,2008:Post/7582008-04-19T11:32:53Z2008-04-19T11:32:53ZTesting flash.now with RSpec<p><code>flash.now</code> has always been a pain to test. The the traditional rails approach is to use <code>assert_select</code> and find it in your views. This clearly doesn’t work if you want to test your controller in isolation.</p>
<p>Other folks have found work arounds to the problem, including <a href="http://rspec.lighthouseapp.com/projects/5645/tickets/98-11834-fake-controller-flash-object">mocking out the flash</a> or <a href="http://www.pluitsolutions.com/2008/01/22/testing-flashnow-in-rails/">monkey patching</a> it.</p>
<p>These solutions feel a bit like using a sledgehammer to me. If you’re going to monkey patch/mock something, you want it to be as discreet as possible so to minimize the chance of the implementation changing underneath you and also to reduce the affect on other areas of your application. Also, why duplicate perfectly good code that is provided elsewhere?</p>
<p>The real problem with testing <code>flash.now</code> is that it gets cleaned up (via <code>#sweep</code>) at the end of the action before you get to test anything. So let’s solve that problem and that problem only: disable sweeping of <code>flash.now</code>:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="c"># spec/spec_helper.rb</span><tt>
</tt><span class="r">module</span> <span class="cl">DisableFlashSweeping</span><tt>
</tt> <span class="r">def</span> <span class="fu">sweep</span><tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="c"># A spec</span><tt>
</tt>describe <span class="co">BogusController</span>, <span class="s"><span class="dl">"</span><span class="k">handling GET to #index</span><span class="dl">"</span></span> <span class="r">do</span><tt>
</tt> it <span class="s"><span class="dl">"</span><span class="k">sets flash.now[:message]</span><span class="dl">"</span></span> <span class="r">do</span><tt>
</tt> <span class="iv">@controller</span>.instance_eval { flash.extend(<span class="co">DisableFlashSweeping</span>) }<tt>
</tt> get <span class="sy">:index</span><tt>
</tt> flash.now[<span class="sy">:message</span>].should_not be_nil<tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p><code>instance_eval</code> is used to access the flash, since it’s a protected method, and we extend with the minimum possible code to do what we want – blanking out the sweep method. This should not cause problems because sweeping is only relevant across multiple requests, which we shouldn’t be doing in our controller specs.</p>