tag:www.rhnh.net,2008:/rspecRspec - Xavier Shay's Blog2011-09-03T22:46:34ZEnkiXavier Shaynotreal@rhnh.nettag:www.rhnh.net,2008:Post/8502011-07-30T05:45:00Z2011-09-03T22:46:34ZInterface Mocking<p><strong><span class="caps">UPDATE</span>:</strong> This is a gem now: <a href="https://github.com/xaviershay/rspec-fire">rspec-fire</a> The code in the gem is better than that presented here.</p>
<p>Here is a screencast I put together in response to a recent Destroy All Software screencast on <a href="https://www.destroyallsoftware.com/screencasts/catalog/test-isolation-and-refactoring">test isolation and refactoring</a>, showing off an idea I’ve been tinkering around with for automatic validation of your implicit interfaces that you stub in tests.</p>
<p><iframe src="http://player.vimeo.com/video/27079042?title=0&byline=0&portrait=0&color=FFFACD" width="600" height="338" frameborder="0"></iframe><p><a href="http://vimeo.com/27079042">Interface Mocking screencast</a>.</p></p>
<p>Here is the code for <code>InterfaceMocking</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>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>23<tt>
</tt>24<tt>
</tt>25<tt>
</tt>26<tt>
</tt>27<tt>
</tt>28<tt>
</tt>29<tt>
</tt><strong>30</strong><tt>
</tt>31<tt>
</tt>32<tt>
</tt>33<tt>
</tt>34<tt>
</tt>35<tt>
</tt>36<tt>
</tt>37<tt>
</tt>38<tt>
</tt>39<tt>
</tt><strong>40</strong><tt>
</tt>41<tt>
</tt>42<tt>
</tt>43<tt>
</tt>44<tt>
</tt>45<tt>
</tt>46<tt>
</tt>47<tt>
</tt>48<tt>
</tt>49<tt>
</tt><strong>50</strong><tt>
</tt>51<tt>
</tt>52<tt>
</tt>53<tt>
</tt>54<tt>
</tt>55<tt>
</tt>56<tt>
</tt>57<tt>
</tt>58<tt>
</tt>59<tt>
</tt><strong>60</strong><tt>
</tt>61<tt>
</tt>62<tt>
</tt>63<tt>
</tt>64<tt>
</tt>65<tt>
</tt>66<tt>
</tt>67<tt>
</tt>68<tt>
</tt>69<tt>
</tt><strong>70</strong><tt>
</tt>71<tt>
</tt>72<tt>
</tt>73<tt>
</tt>74<tt>
</tt>75<tt>
</tt>76<tt>
</tt>77<tt>
</tt>78<tt>
</tt>79<tt>
</tt><strong>80</strong><tt>
</tt>81<tt>
</tt>82<tt>
</tt>83<tt>
</tt>84<tt>
</tt>85<tt>
</tt>86<tt>
</tt>87<tt>
</tt>88<tt>
</tt>89<tt>
</tt><strong>90</strong><tt>
</tt>91<tt>
</tt>92<tt>
</tt>93<tt>
</tt>94<tt>
</tt>95<tt>
</tt>96<tt>
</tt>97<tt>
</tt>98<tt>
</tt>99<tt>
</tt><strong>100</strong><tt>
</tt>101<tt>
</tt>102<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">module</span> <span class="cl">InterfaceMocking</span><tt>
</tt><tt>
</tt> <span class="c"># Returns a new interface double. This is equivalent to an RSpec double,</span><tt>
</tt> <span class="c"># stub or, mock, except that if the class passed as the first parameter</span><tt>
</tt> <span class="c"># is loaded it will raise if you try to set an expectation or stub on</span><tt>
</tt> <span class="c"># a method that the class has not implemented.</span><tt>
</tt> <span class="r">def</span> <span class="fu">interface_double</span>(stubbed_class, methods = {})<tt>
</tt> <span class="co">InterfaceDouble</span>.new(stubbed_class, methods)<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">module</span> <span class="cl">InterfaceDoubleMethods</span><tt>
</tt><tt>
</tt> include <span class="co">RSpec</span>::<span class="co">Matchers</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">should_receive</span>(method_name)<tt>
</tt> ensure_implemented(method_name)<tt>
</tt> <span class="r">super</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">should_not_receive</span>(method_name)<tt>
</tt> ensure_implemented(method_name)<tt>
</tt> <span class="r">super</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">stub!</span>(method_name)<tt>
</tt> ensure_implemented(method_name)<tt>
</tt> <span class="r">super</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">ensure_implemented</span>(*method_names)<tt>
</tt> <span class="r">if</span> recursive_const_defined?(<span class="co">Object</span>, <span class="iv">@__stubbed_class__</span>)<tt>
</tt> recursive_const_get(<span class="co">Object</span>, <span class="iv">@__stubbed_class__</span>).<tt>
</tt> should implement(method_names, <span class="iv">@__checked_methods__</span>)<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">recursive_const_get</span> object, name<tt>
</tt> name.split(<span class="s"><span class="dl">'</span><span class="k">::</span><span class="dl">'</span></span>).inject(<span class="co">Object</span>) {|klass,name| klass.const_get name }<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">recursive_const_defined?</span> object, name<tt>
</tt> !!name.split(<span class="s"><span class="dl">'</span><span class="k">::</span><span class="dl">'</span></span>).inject(<span class="co">Object</span>) {|klass,name|<tt>
</tt> <span class="r">if</span> klass && klass.const_defined?(name)<tt>
</tt> klass.const_get name<tt>
</tt> <span class="r">end</span><tt>
</tt> }<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">class</span> <span class="cl">InterfaceDouble</span> < <span class="co">RSpec</span>::<span class="co">Mocks</span>::<span class="co">Mock</span><tt>
</tt><tt>
</tt> include <span class="co">InterfaceDoubleMethods</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">initialize</span>(stubbed_class, *args)<tt>
</tt> args << {} <span class="r">unless</span> <span class="co">Hash</span> === args.last<tt>
</tt><tt>
</tt> <span class="iv">@__stubbed_class__</span> = stubbed_class<tt>
</tt> <span class="iv">@__checked_methods__</span> = <span class="sy">:public_instance_methods</span><tt>
</tt> ensure_implemented *args.last.keys<tt>
</tt><tt>
</tt> <span class="c"># __declared_as copied from rspec/mocks definition of `double`</span><tt>
</tt> args.last[<span class="sy">:__declared_as</span>] = <span class="s"><span class="dl">'</span><span class="k">InterfaceDouble</span><span class="dl">'</span></span><tt>
</tt> <span class="r">super</span>(stubbed_class, *args)<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="co">RSpec</span>::<span class="co">Matchers</span>.define <span class="sy">:implement</span> <span class="r">do</span> |expected_methods, checked_methods|<tt>
</tt> match <span class="r">do</span> |stubbed_class|<tt>
</tt> unimplemented_methods(<tt>
</tt> stubbed_class,<tt>
</tt> expected_methods,<tt>
</tt> checked_methods<tt>
</tt> ).empty?<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">unimplemented_methods</span>(stubbed_class, expected_methods, checked_methods)<tt>
</tt> implemented_methods = stubbed_class.send(checked_methods)<tt>
</tt> unimplemented_methods = expected_methods - implemented_methods<tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> failure_message_for_should <span class="r">do</span> |stubbed_class|<tt>
</tt> <span class="s"><span class="dl">"</span><span class="k">%s does not publicly implement:</span><span class="ch">\n</span><span class="k">%s</span><span class="dl">"</span></span> % [<tt>
</tt> stubbed_class,<tt>
</tt> unimplemented_methods(<tt>
</tt> stubbed_class,<tt>
</tt> expected_methods,<tt>
</tt> checked_methods<tt>
</tt> ).sort.map {|x|<tt>
</tt> <span class="s"><span class="dl">"</span><span class="k"> </span><span class="il"><span class="idl">#{</span>x<span class="idl">}</span></span><span class="dl">"</span></span><tt>
</tt> }.join(<span class="s"><span class="dl">"</span><span class="ch">\n</span><span class="dl">"</span></span>)<tt>
</tt> ]<tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="co">RSpec</span>.configure <span class="r">do</span> |config|<tt>
</tt><tt>
</tt> config.include <span class="co">InterfaceMocking</span><tt>
</tt><tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
tag:www.rhnh.net,2008:Post/8372010-10-06T23:31:02Z2010-10-06T23:31:02ZTransactional before all with RSpec and DataMapper<p>By default, <code>before(:all)</code> in rspec executes <em>outside</em> of any transaction, meaning that you can’t really use it for creating objects. Normally this should go in a <code>before(:each)</code>, but for a spec with simple creation and a large number of assertions this is terribly inefficient.</p>
<p>Let’s fix it!</p>
<p>This code assumes you are using DataMapper, and that your database supports some form of nested transactions (at the very least faking them with savepoints – see <a href="http://rhnh.net/2010/10/06/nested-transactions-in-postgres-with-datamapper">nested transactions in postgres with datamapper</a>). It wraps each before/after <code>:all</code> and <code>:each</code> in it’s own transaction.</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>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="co">RSpec</span>.configure <span class="r">do</span> |config|<tt>
</tt> [<span class="sy">:all</span>, <span class="sy">:each</span>].each <span class="r">do</span> |x|<tt>
</tt> config.before(x) <span class="r">do</span><tt>
</tt> repository(<span class="sy">:default</span>) <span class="r">do</span> |repository|<tt>
</tt> transaction = <span class="co">DataMapper</span>::<span class="co">Transaction</span>.new(repository)<tt>
</tt> transaction.begin<tt>
</tt> repository.adapter.push_transaction(transaction)<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> config.after(x) <span class="r">do</span><tt>
</tt> repository(<span class="sy">:default</span>).adapter.pop_transaction.rollback<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> config.include(<span class="co">RSpecExtensions</span>::<span class="co">Set</span>)<tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p>See that <code>RSpecExtensions::Set</code> include? That’s a version of the lovely <code>let</code> helpers that works with before(:all) setup. Props to <a href="http://twitter.com/pcreux">pcreux</a> for this:</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>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>23<tt>
</tt>24<tt>
</tt>25<tt>
</tt>26<tt>
</tt>27<tt>
</tt>28<tt>
</tt>29<tt>
</tt><strong>30</strong><tt>
</tt>31<tt>
</tt>32<tt>
</tt>33<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">module</span> <span class="cl">RSpecExtensions</span><tt>
</tt> <span class="r">module</span> <span class="cl">Set</span><tt>
</tt><tt>
</tt> <span class="r">module</span> <span class="cl">ClassMethods</span><tt>
</tt> <span class="c"># Generates a method whose return value is memoized</span><tt>
</tt> <span class="c"># in before(:all). Great for DB setup when combined with</span><tt>
</tt> <span class="c"># transactional before alls.</span><tt>
</tt> <span class="r">def</span> <span class="fu">set</span>(name, &block)<tt>
</tt> define_method(name) <span class="r">do</span><tt>
</tt> __memoized[name] ||= instance_eval(&block)<tt>
</tt> <span class="r">end</span><tt>
</tt> before(<span class="sy">:all</span>) { __send__(name) }<tt>
</tt> before(<span class="sy">:each</span>) <span class="r">do</span><tt>
</tt> __send__(name).tap <span class="r">do</span> |obj|<tt>
</tt> obj.reload <span class="r">if</span> obj.respond_to?(<span class="sy">:reload</span>)<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">module</span> <span class="cl">InstanceMethods</span><tt>
</tt> <span class="r">def</span> <span class="fu">__memoized</span> <span class="c"># :nodoc:</span><tt>
</tt> <span class="iv">@__memoized</span> ||= {}<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="pc">self</span>.included(mod) <span class="c"># :nodoc:</span><tt>
</tt> mod.extend <span class="co">ClassMethods</span><tt>
</tt> mod.__send__ <span class="sy">:include</span>, <span class="co">InstanceMethods</span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p>Fast specs make me a happy man.</p>tag:www.rhnh.net,2008:Post/7862008-10-01T06:11:00Z2008-10-01T06:11:51ZIntegration testing with Cucumber, RSpec and Thinking Sphinx<p>Ideally you would want to include sphinx in your integration tests. It’s really just like your database. In practice, this is problematic. Ensuring the DB is started and triggering a re-index after each model load is doable, if slow, with a small bit of hacking of thinking sphinx (hint – change the initializer for the <code>ThinkingSphinx::Configuration</code> to allow you to specify the environment). Here’s the rub though – if you’re using transactional fixtures the sphinx indexer won’t be able to see any of your data! Turning that off can really slow down your tests, and once you add in the re-indexing time you’re going to be making a few cups of coffee while they run.</p>
<p>One approach I’ve been taking is to stub out the <code>search</code> methods with <a href="http://github.com/btakita/rr/tree/master">RR</a>. I know, I know, stubbing in your integration tests is evil. I’m being pragmatic here. For most applications your search is trivial (find me results for this keyword), and if you unit test your <code>define_index</code> block you’re pretty well covered. To go one step further you could unit test your controllers with an expect on the search method, or have a separate suite of non-transactional integration tests running against sphinx. I like the latter, but haven’t done it yet.</p>
<p>Enough talk! Here’s the magic you need to get it working with <a href="http://github.com/aslakhellesoy/cucumber/tree/master">cucumber</a>:</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></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="c"># features/steps/env.rb</span><tt>
</tt>require <span class="s"><span class="dl">'</span><span class="k">rr</span><span class="dl">'</span></span><tt>
</tt><span class="co">Cucumber</span>::<span class="co">Rails</span>::<span class="co">World</span>.send(<span class="sy">:include</span>, <span class="co">RR</span>::<span class="co">Adapters</span>::<span class="co">RRMethods</span>)<tt>
</tt><tt>
</tt><span class="c"># features/steps/*_steps.rb</span><tt>
</tt><span class="co">Given</span> <span class="rx"><span class="dl">/</span><span class="k">a car with model '(</span><span class="ch">\w</span><span class="k">+)' exists</span><span class="dl">/</span></span> <span class="r">do</span> |model|<tt>
</tt> car = <span class="co">Car</span>.create!(<span class="sy">:model</span> => model)<tt>
</tt> stub(<span class="co">Car</span>).search(model) { [car] }<tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
tag: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>