<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Chris Said So]]></title>
  <link href="http://chriskottom.com/atom.xml" rel="self"/>
  <link href="http://chriskottom.com/"/>
  <updated>2018-01-15T12:34:57+01:00</updated>
  <id>http://chriskottom.com/</id>
  <author>
    <name><![CDATA[Chris Kottom]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Comparing Timestamps in Rails]]></title>
    <link href="http://chriskottom.com/blog/2018/01/comparing-timestamps-in-rails/"/>
    <updated>2018-01-14T17:48:05+01:00</updated>
    <id>http://chriskottom.com/blog/2018/01/comparing-timestamps-in-rails</id>
    <content type="html"><![CDATA[<p>The Ruby core language and standard library include two classes that represent timestamps: Time and DateTime.  And even though they fill similar needs, they have different internals and aren&rsquo;t comparable.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="nb">require</span> <span class="s1">&#39;date&#39;</span>
</span><span class='line'><span class="kp">true</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time</span> <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span>
</span><span class='line'><span class="mi">2018</span><span class="o">-</span><span class="mo">01</span><span class="o">-</span><span class="mi">14</span> <span class="mi">16</span><span class="p">:</span><span class="mi">40</span><span class="p">:</span><span class="mi">29</span> <span class="o">+</span><span class="mo">0100</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">datetime</span> <span class="o">=</span> <span class="no">DateTime</span><span class="o">.</span><span class="n">now</span>
</span><span class='line'><span class="c1">#&lt;DateTime: 2018-01-14T16:40:40+01:00 ((2458133j,56440s,60191240n),+3600s,2299161j)&gt;</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time</span> <span class="o">&lt;</span> <span class="n">datetime</span>
</span><span class='line'><span class="ss">ArgumentError</span><span class="p">:</span> <span class="n">comparison</span> <span class="n">of</span> <span class="no">Time</span> <span class="n">with</span> <span class="no">DateTime</span> <span class="n">failed</span>
</span><span class='line'>      <span class="n">from</span> <span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">5</span><span class="ss">:in</span> <span class="sb">`&lt;&#39;</span>
</span><span class='line'><span class="sb">     from (irb):5</span>
</span><span class='line'><span class="sb">     from /home/chris/.rbenv/versions/2.4.2/bin/irb:11:in `</span><span class="o">&lt;</span><span class="n">main</span><span class="o">&gt;</span><span class="err">&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Rails adds the ActiveSupport::TimeWithZone class and extends the core classes in a number of ways including by allowing comparison of instances of different classes:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">005</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="nb">require</span> <span class="s1">&#39;active_support&#39;</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">true</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">006</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="nb">require</span> <span class="s1">&#39;active_support/core_ext&#39;</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">true</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">007</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time</span> <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">2018</span><span class="o">-</span><span class="mo">01</span><span class="o">-</span><span class="mi">14</span> <span class="mi">16</span><span class="p">:</span><span class="mi">43</span><span class="p">:</span><span class="mi">18</span> <span class="o">+</span><span class="mo">0100</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">8</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">datetime</span> <span class="o">=</span> <span class="no">DateTime</span><span class="o">.</span><span class="n">now</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="no">Sun</span><span class="p">,</span> <span class="mi">14</span> <span class="no">Jan</span> <span class="mi">2018</span> <span class="mi">16</span><span class="p">:</span><span class="mi">43</span><span class="p">:</span><span class="mi">24</span> <span class="o">+</span><span class="mo">0100</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">9</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time</span> <span class="o">&lt;</span> <span class="n">datetime</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">true</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">010</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="no">Time</span><span class="o">.</span><span class="n">zone</span> <span class="o">=</span> <span class="s1">&#39;Eastern Time (US &amp; Canada)&#39;</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s2">&quot;Eastern Time (US &amp; Canada)&quot;</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">011</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span> <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">zone</span><span class="o">.</span><span class="n">now</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="no">Sun</span><span class="p">,</span> <span class="mi">14</span> <span class="no">Jan</span> <span class="mi">2018</span> <span class="mi">10</span><span class="p">:</span><span class="mi">44</span><span class="p">:</span><span class="mi">10</span> <span class="no">EST</span> <span class="o">-</span><span class="mo">05</span><span class="p">:</span><span class="mo">00</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">012</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">date</span> <span class="o">&lt;</span> <span class="n">time_with_zone</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">true</span>
</span></code></pre></td></tr></table></div></figure>


<p>In most cases, this frees you up to write code without having to explicitly convert between types or even know which types you&rsquo;re comparing.  But eventually you might find yourself try to test the equality of two timestamps which should logically be the same:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">assert_equal</span> <span class="n">email</span><span class="o">.</span><span class="n">sent_at</span><span class="p">,</span> <span class="n">email_delivery</span><span class="o">.</span><span class="n">created_at</span>
</span></code></pre></td></tr></table></div></figure>


<p>The error message in this case only deepens the mystery:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>No visible difference in the ActiveSupport::TimeWithZone#inspect output.
</span><span class='line'>You should look at the implementation of #== on ActiveSupport::TimeWithZone or its members.
</span><span class='line'>Sun, 14 Jan 2018 11:13:40 EST -05:00</span></code></pre></td></tr></table></div></figure>


<p>The thing to remember here is that all of these classes store timestamps with much more precision than they usually display.  In the case of ActiveSupport::TimeWithZone, that goes down to millisecond and even nanosecond precision.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">013</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span><span class="o">.</span><span class="n">to_s</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s2">&quot;2018-01-14 10:44:10 -0500&quot;</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">014</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span><span class="o">.</span><span class="n">to_i</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">1515944650</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">015</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span><span class="o">.</span><span class="n">to_f</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">1515944650</span><span class="o">.</span><span class="mi">4874508</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">016</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span><span class="o">.</span><span class="n">usec</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">487450</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">017</span><span class="p">:</span><span class="mi">0</span><span class="o">&gt;</span> <span class="n">time_with_zone</span><span class="o">.</span><span class="n">nsec</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">487450777</span>
</span></code></pre></td></tr></table></div></figure>


<p>So when we want to compare timestamps that we know to be unequal, the usual operators (<code>&gt;</code>, <code>&lt;</code>, …) are fine.  But if we&rsquo;re checking for relative equality, we&rsquo;ll need to use some representations of the timestamps.</p>

<p>In <a href="https://chriskottom.com/minitestcookbook/">The Minitest Cookbook</a> I advised developers to compare dates and times using a string representation since, when you do fail a test, the message returned will usually be meaningful.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">send_time</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">sent_at</span>
</span><span class='line'><span class="n">assert_equal</span> <span class="s2">&quot;2017-11-02 17:09&quot;</span><span class="p">,</span> <span class="n">send_time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%Y-%m-%d %H:%M&quot;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>I still think that&rsquo;s the way to go when you&rsquo;re comparing generated data with a constant value, but in other cases like where you&rsquo;re checking the equality of two generated values, it&rsquo;s usually better to compare numeric representations of the timestamps as:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">send_time</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">sent_at</span>
</span><span class='line'><span class="n">delivery_time</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">delivery</span><span class="o">.</span><span class="n">created_at</span>
</span><span class='line'><span class="n">assert_equal</span> <span class="n">send_time</span><span class="o">.</span><span class="n">to_i</span><span class="p">,</span> <span class="n">delivery_time</span><span class="o">.</span><span class="n">to_i</span>
</span></code></pre></td></tr></table></div></figure>


<p>Keep in mind that there&rsquo;s always the chance that the two timestamps might be generated across a second boundary which would cause the test as written to fail.  If you&rsquo;re looking for some additional insurance for this situation, you could also assert that the numeric representations of the timestamps are within a delta of one another:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">send_time</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">sent_at</span>
</span><span class='line'><span class="n">delivery_time</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">delivery</span><span class="o">.</span><span class="n">created_at</span>
</span><span class='line'><span class="n">delta</span> <span class="o">=</span> <span class="mi">0</span><span class="o">.</span><span class="mo">01</span>
</span><span class='line'><span class="n">assert_in_delta</span> <span class="n">send_time</span><span class="o">.</span><span class="n">to_f</span><span class="p">,</span> <span class="n">delivery_time</span><span class="o">.</span><span class="n">to_f</span><span class="p">,</span> <span class="n">delta</span>
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rails Helper Testing Made Simple]]></title>
    <link href="http://chriskottom.com/blog/2017/06/rails-helper-testing-made-simple/"/>
    <updated>2017-06-13T11:46:47+02:00</updated>
    <id>http://chriskottom.com/blog/2017/06/rails-helper-testing-made-simple</id>
    <content type="html"><![CDATA[<p>Rails relies on a standard project structure and a strong set of conventions to keep things neat and tidy - models separated from controllers, configuration in another folder structured just so. The exception that proves the rule in this case, though, would have to be Rails view helpers. Helpers tend to be a dumping ground for all the random bits of view logic, formatting, and utility code that accumulate in every web application, and if you&rsquo;re not disciplined (and most of us aren&rsquo;t), <code>app/helpers</code> can degenerate into a jungle quickly.</p>

<p>But helpers fill a necessary role in our applications by removing presentation logic from our templates and moving it to methods which makes it easier to test. So even though they&rsquo;re going to be hard to organize almost by definition, we can still be disciplined about testing them. In other words: your view helpers might still look like spaghetti, but at least we can make sure it&rsquo;s well-tested spaghetti.<!--more--></p>

<h2>The Only Two Things You Need to Know About Helpers</h2>

<p>Faced with a collection of arbitrary functions, many developers skip testing helpers altogether. A lot of my older applications have zero tests for helpers, and it was mostly because the benefits just didn&rsquo;t seem to justify the effort required. That changed the day I came to two important realizations. First, understand that <strong>helpers are just Ruby mixins</strong>. From a testing perspective, there&rsquo;s nothing special or unusual about them, and that means that we can apply <a href="http://chriskottom.com/blog/2015/03/testing-ruby-mixins-in-isolation/">the same tools and techniques that we already use to test other kind of mixins</a>.</p>

<p>Second, since they&rsquo;re just modules mixed into the view, <strong>there are only two types of helpers we need to consider</strong>: methods that depend on the thing they&rsquo;re mixed into, and methods that don&rsquo;t. The rest of this post will explain how to know which type of method you&rsquo;re dealing with and how to write a test for it once you do.</p>

<h2>Testing Standalone Helpers</h2>

<p>A standalone helper for our purposes is essentially a <a href="https://en.wikipedia.org/wiki/Pure_function">pure function</a> - a method whose return value is based solely on the inputs given to and which produces no other side effects. Common examples of these include methods used to format numbers, dates and text stored in a model for display or those that wrap other Rails view helpers to add more specific functionality - usually anywhere from 50-90% of helpers. The block below shows just a sample of the types of methods I mean:</p>

<figure class='code'><figcaption><span>app/helpers/products_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">ProductsHelper</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">link_to_product</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>    <span class="n">link_to</span> <span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">product</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">product_thumbnail</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>    <span class="n">image_tag</span> <span class="n">product</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">url</span><span class="p">(</span><span class="ss">:thumbnail</span><span class="p">),</span> <span class="ss">alt</span><span class="p">:</span> <span class="n">product</span><span class="o">.</span><span class="n">name</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">product_price</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>    <span class="n">tag</span><span class="o">.</span><span class="n">span</span> <span class="n">number_to_currency</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">price</span><span class="p">),</span> <span class="ss">class</span><span class="p">:</span> <span class="s1">&#39;price&#39;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">product_list_entry</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>    <span class="n">tag</span><span class="o">.</span><span class="n">div</span><span class="p">(</span><span class="nb">id</span><span class="p">:</span> <span class="s2">&quot;product-</span><span class="si">#{</span> <span class="n">product</span><span class="o">.</span><span class="n">id</span> <span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="ss">class</span><span class="p">:</span> <span class="s1">&#39;product&#39;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">content</span>  <span class="o">=</span> <span class="n">product_thumbnail</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>      <span class="n">content</span> <span class="o">+=</span> <span class="n">tag</span><span class="o">.</span><span class="n">span</span><span class="p">(</span><span class="n">link_to_product</span><span class="p">(</span><span class="n">product</span><span class="p">),</span> <span class="ss">class</span><span class="p">:</span> <span class="s1">&#39;name&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="n">content</span> <span class="o">+=</span> <span class="n">product_price</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
</span><span class='line'>      <span class="n">content</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>While the Rails view mixes in all your helper modules with every request, helper tests based on ActionView::TestCase only include the helper module currently under test. The result, though, is that methods from the helper are available as part of the test, so we can call them directly as you see in the test below.</p>

<figure class='code'><figcaption><span>test/helpers/products_helper_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ProductsHelperTest</span> <span class="o">&lt;</span> <span class="ss">ActionView</span><span class="p">:</span><span class="ss">:TestCase</span>
</span><span class='line'>  <span class="n">setup</span> <span class="k">do</span>
</span><span class='line'>    <span class="vi">@product</span> <span class="o">=</span> <span class="n">products</span><span class="p">(</span><span class="ss">:bacon</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#link_to_product produces a product link&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="s2">&quot;&lt;a href=</span><span class="se">\&quot;</span><span class="si">#{</span> <span class="n">product_path</span><span class="p">(</span><span class="vi">@product</span><span class="p">)</span> <span class="si">}</span><span class="se">\&quot;</span><span class="s2">&gt;</span><span class="si">#{</span> <span class="vi">@product</span><span class="o">.</span><span class="n">name</span> <span class="si">}</span><span class="s2">&lt;/a&gt;&quot;</span><span class="p">,</span>
</span><span class='line'>                 <span class="n">link_to_product</span><span class="p">(</span><span class="vi">@product</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#product_list_entry contains a thumbnail image&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">image_regexp</span> <span class="o">=</span> <span class="sr">/src=&quot;</span><span class="si">#{</span> <span class="vi">@product</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">url</span><span class="p">(</span><span class="ss">:thumbnail</span><span class="p">)</span> <span class="si">}</span><span class="sr">&quot;/</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="n">image_regexp</span><span class="p">,</span> <span class="n">product_list_entry</span><span class="p">(</span><span class="vi">@product</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#product_list_entry contains the product name&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/</span><span class="si">#{</span> <span class="vi">@product</span><span class="o">.</span><span class="n">name</span> <span class="si">}</span><span class="sr">/</span><span class="p">,</span> <span class="n">product_list_entry</span><span class="p">(</span><span class="vi">@product</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#product_list_entry contains the product price&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/\$</span><span class="si">#{</span> <span class="vi">@product</span><span class="o">.</span><span class="n">price</span> <span class="si">}</span><span class="sr">/</span><span class="p">,</span> <span class="n">product_list_entry</span><span class="p">(</span><span class="vi">@product</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Testing methods like this is simple - given known inputs, make assertions about the outputs. Another common Rails pattern is a helper method that takes a block parameter. Methods like these can be used to generate markup that will be wrap code defined in the template. One example might be a helper that takes a block and prepares a form tag specifically tailored to a given model class and interface type.</p>

<figure class='code'><figcaption><span>app/helpers/products_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">ProductsHelper</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">product_form_with</span><span class="p">(</span><span class="o">**</span><span class="n">params</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'>    <span class="n">params</span><span class="o">[</span><span class="ss">:model</span><span class="o">]</span> <span class="o">||=</span> <span class="no">Product</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="n">params</span><span class="o">[</span><span class="ss">:class</span><span class="o">]</span>
</span><span class='line'>      <span class="n">params</span><span class="o">[</span><span class="ss">:class</span><span class="o">]</span> <span class="o">+=</span> <span class="s1">&#39; product form-horizontal&#39;</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>      <span class="n">params</span><span class="o">[</span><span class="ss">:class</span><span class="o">]</span> <span class="o">=</span> <span class="s1">&#39;product form-horizontal&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">form_with</span><span class="p">(</span><span class="o">**</span><span class="n">params</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span>
</span><span class='line'>      <span class="k">yield</span> <span class="n">form</span> <span class="k">if</span> <span class="nb">block_given?</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>When testing a method like this, it&rsquo;s possible to make assertions about the parameters passed to the block argument in addition to the return value as you see in the example test.</p>

<figure class='code'><figcaption><span>test/helpers/products_helper_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ProductsHelperTest</span> <span class="o">&lt;</span> <span class="ss">ActionView</span><span class="p">:</span><span class="ss">:TestCase</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#product_form_with adds classes to the form&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/class=&quot;[^&quot;]*product form\-horizontal&quot;/</span><span class="p">,</span> <span class="n">product_form_with</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#product_form_with sets the object to a new instance if not present&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">product_form_with</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span>
</span><span class='line'>      <span class="n">product</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">object</span>
</span><span class='line'>      <span class="sx">%w(id name price created_at updated_at)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">attr_name</span><span class="o">|</span>
</span><span class='line'>        <span class="n">assert_nil</span> <span class="n">product</span><span class="o">[</span><span class="n">attr_name</span><span class="o">]</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>      <span class="n">assert</span> <span class="n">product</span><span class="o">.</span><span class="n">new_record?</span><span class="p">,</span> <span class="s1">&#39;Expected product to be new&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Testing Helpers That Depend on the View</h2>

<p>In most cases, I find it cleaner to write helper methods as pure functions by passing in all the state needed to evaluate it. But in certain cases, it&rsquo;s better to let helpers be helpers by not being ignorant about their relationship to the view. Case in point: a friend of mine shared an example with me a few weeks ago where he was working on building up a string of DOM classes in the view. He&rsquo;d written a method like the one below to generate the class for the link to the current URL:</p>

<figure class='code'><figcaption><span>app/helpers/pages_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">PagesHelper</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">active?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span><span class='line'>    <span class="s1">&#39;active&#39;</span> <span class="k">if</span> <span class="n">current_page?</span> <span class="n">path</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This could have been written by passing in the Boolean result of <code>current_page?(path)</code>, but the route he chose was definitely cleaner and more Rails-like. The problem that he was having, though, was: how best to test this?</p>

<p>My advice to him was first to understand what you don&rsquo;t need to test. Specifically, you don&rsquo;t have to care how <code>current_page?</code> arrives at a result, you only care about the result itself and what your code does with it. Once you realize that, then all you need is to stub the possible values of that method and make assertions about what your code returns.</p>

<p>Here again, the helper module and all the Rails standard view helpers are mixed directly into the test case, so the test behaves just like a Rails view. We can stub <code>current_page?</code> directly in the test like this:</p>

<figure class='code'><figcaption><span>test/helpers/pages_helper_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">PagesHelperTest</span> <span class="o">&lt;</span> <span class="ss">ActionView</span><span class="p">:</span><span class="ss">:TestCase</span>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#active? page returns true for current_page?&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">stub</span> <span class="ss">:current_page?</span><span class="p">,</span> <span class="kp">true</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_equal</span> <span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="n">active?</span><span class="p">(</span><span class="s1">&#39;pages/some/path&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;#active? page returns nil on any other page&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">stub</span> <span class="ss">:current_page?</span><span class="p">,</span> <span class="kp">false</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_nil</span> <span class="n">active?</span><span class="p">(</span><span class="s1">&#39;pages/other/path&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Is Testing Helpers Worth Your Time?</h2>

<p>I don&rsquo;t test every single helper that I write. There&rsquo;s just very little return on the time you spend writing a test for a function that formats the current date or wraps a call to <code>link_to</code>. Through experience though, I&rsquo;ve become more aware when I find myself writing a helper that probably needs to be tested. Any methods with the following characteristics are usually good candidates:</p>

<ul>
<li>Contains conditionals or <code>switch</code> statements</li>
<li>Long methods (> 10 LOC including any executed private methods)</li>
<li>Uses String composition to generate complex markup</li>
<li>Takes more than one parameter</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Full-Stack Testing with Rails System Tests]]></title>
    <link href="http://chriskottom.com/blog/2017/04/full-stack-testing-with-rails-system-tests/"/>
    <updated>2017-04-26T08:29:46+02:00</updated>
    <id>http://chriskottom.com/blog/2017/04/full-stack-testing-with-rails-system-tests</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/unit-tests-passing-no-integration-tests.jpg" width="400" title="Two unit tests passing, no integration tests" >
Ruby on Rails&#8217; bundled support for automated testing has contributed to building a culture of testing within the community, but it&rsquo;s also been a source of some debate. Differences in testing styles and preferences have spawned long-running discussions and flame wars over the years. Most of this amounts to bikeshedding, but if there&rsquo;s one area where The Rails Way has lagged behind RSpec, it&rsquo;s been in the area of end-to-end application testing. RSpec has long had expressive feature specs based on <a href="https://github.com/teamcapybara/capybara">Capybara</a>, while Rails default integration tests, though functional, have never been as expressive.</p>

<p>With the release of version 5.1, Rails introduces <strong>system tests</strong> built on Capybara. These look like just the thing to fill this longstanding gap, and the fact that they&rsquo;ll be configured to work right out of the box with no additional setup required will make it easier for more developers to start using them. In this post, we&rsquo;re going to look at the approach Rails takes toward system tests and what kind of advantages they offer over both old-school integration tests and current solutions for testing apps with Capybara.<!--more--></p>

<h2>Baseline: A Rails Integration Test</h2>

<p>Up until now, the standard solution for testing complex interactions spanning multiple page views has been the <strong>integration test</strong>. It provides basic support for sending requests to the application and making assertions about the responses - the status code, headers, and response HTML - and it does all of this withing the context of a virtual session which gives the test access to persistent state such as session data and Rails flash. (Since Rails 5.0, controller tests have also inherited from the same <code>ActionDispatch::IntegrationTest</code> class making these functionally, if not logically, equivalent.)</p>

<p>This example shows how an integration test can be used to simulate the creation of a new User over several requests.</p>

<figure class='code'><figcaption><span>test/integration/create_new_user_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">CreateNewUserTest</span> <span class="o">&lt;</span> <span class="ss">ActionDispatch</span><span class="p">:</span><span class="ss">:IntegrationTest</span>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;creating a new User&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="c1"># Visit the index page</span>
</span><span class='line'>    <span class="n">get</span> <span class="n">users_url</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;New User&#39;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Click the New User link</span>
</span><span class='line'>    <span class="n">get</span> <span class="n">new_user_url</span>
</span><span class='line'>    <span class="n">assert_response</span> <span class="ss">:ok</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;h1&#39;</span><span class="p">,</span> <span class="s1">&#39;New User&#39;</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;form&#39;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_select</span> <span class="s1">&#39;input#user_email&#39;</span>
</span><span class='line'>      <span class="n">assert_select</span> <span class="s1">&#39;input#user_password&#39;</span>
</span><span class='line'>      <span class="n">assert_select</span> <span class="s1">&#39;input#user_password_confirmation&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Submit the form</span>
</span><span class='line'>    <span class="n">user_attributes</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>      <span class="ss">email</span><span class="p">:</span> <span class="s1">&#39;user1@example.com&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="ss">password</span><span class="p">:</span> <span class="s1">&#39;secret&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="n">password_confirmation</span><span class="p">:</span> <span class="s1">&#39;secret&#39;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="n">post</span> <span class="n">users_url</span><span class="p">,</span> <span class="ss">params</span><span class="p">:</span> <span class="p">{</span> <span class="ss">user</span><span class="p">:</span> <span class="n">user_attributes</span> <span class="p">}</span>
</span><span class='line'>    <span class="n">assert_response</span> <span class="ss">:redirect</span>
</span><span class='line'>    <span class="n">follow_redirect!</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Verify that the User was created</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;#notice&#39;</span><span class="p">,</span> <span class="s1">&#39;User was successfully created.&#39;</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;#email&#39;</span><span class="p">,</span> <span class="s2">&quot;Email:</span><span class="se">\n</span><span class="s2">  user1@example.com&quot;</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;Back&#39;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Verify that User appears in listing</span>
</span><span class='line'>    <span class="n">get</span> <span class="n">users_url</span>
</span><span class='line'>    <span class="n">assert_select</span> <span class="s1">&#39;table&#39;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_select</span> <span class="s1">&#39;tr td&#39;</span><span class="p">,</span> <span class="s1">&#39;user1@example.com&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>At first glance, we see that the test is written using technical language. Requests are defined as interactions between the test and the server, not between the user and the interface. It also assumes a certain amount of knowledge about the application&rsquo;s implementation. For example, in some places the test asserts the presence of an element on the page and then takes an action we know to be associated with that element. The connection between the element and the action is only implied, never direct.</p>

<p>Integration tests also only ever look at the HTML that&rsquo;s rendered by the server, ignoring any changes made by JavaScript running in the browser. In modern web applications, the DOM is a living, breathing thing, so while naive tests like this were adequate back in the days of Basecamp version 1 it&rsquo;s not enough for most current apps.</p>

<h2>Moving to System Tests</h2>

<figure class="right" style="margin:0 0 15px 15px">
  <img class="no-border" src="http://chriskottom.com/images/capybara-god-of-thunder.jpg" style="margin:0">
  <figcaption style="text-align:center;margin-top:0px">
    Capybara, God of Thunder<br/>(Actually, looks more like a woodchuck to me)
  </figcaption>
</figure>


<p>System tests occupy a role similar to integration tests, but they add several important features that make them even more well suited to the kinds of applications we&rsquo;re building today. By leveraging Capybara, which is already mature and well-known to much of the Rails community, they&rsquo;ve been able to avoid reinventing the wheel and have instead focused on integration with the framework and the existing testing tools to ensure ease of use.</p>

<p class="clearfix">This example system test is roughly equivalent to the integration test we looked at before.</p>




<figure class='code'><figcaption><span>test/system/users_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;application_system_test_case&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">UsersTest</span> <span class="o">&lt;</span> <span class="no">ApplicationSystemTestCase</span>
</span><span class='line'>  <span class="nb">test</span> <span class="s1">&#39;creating a new User&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="c1"># Visit the index page</span>
</span><span class='line'>    <span class="n">visit</span> <span class="n">users_url</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Click the New User link</span>
</span><span class='line'>    <span class="n">click_link</span> <span class="s1">&#39;New User&#39;</span>
</span><span class='line'>    <span class="n">assert_selector</span> <span class="s1">&#39;h1&#39;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="s1">&#39;New User&#39;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Submit the form</span>
</span><span class='line'>    <span class="n">fill_in</span> <span class="s1">&#39;Email&#39;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s1">&#39;user1@example.com&#39;</span>
</span><span class='line'>    <span class="n">fill_in</span> <span class="s1">&#39;Password&#39;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s1">&#39;secret&#39;</span>
</span><span class='line'>    <span class="n">fill_in</span> <span class="s1">&#39;Password confirmation&#39;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s1">&#39;secret&#39;</span>
</span><span class='line'>    <span class="n">click_button</span> <span class="s1">&#39;Create User&#39;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Verify that the User was created</span>
</span><span class='line'>    <span class="n">assert_selector</span> <span class="s1">&#39;#notice&#39;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="s1">&#39;User was successfully created.&#39;</span>
</span><span class='line'>    <span class="n">assert_selector</span> <span class="s1">&#39;#email&#39;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="s1">&#39;Email: user1@example.com&#39;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1"># Verify that User appears in listing</span>
</span><span class='line'>    <span class="n">click_link</span> <span class="s1">&#39;Back&#39;</span>
</span><span class='line'>    <span class="n">within</span> <span class="s1">&#39;table&#39;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_selector</span> <span class="s1">&#39;tr td&#39;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="s1">&#39;user1@example.com&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Capybara&rsquo;s DSL (<a href="https://gist.github.com/zhengjia/428105">see this cheat sheet</a>) lets you define test cases using the same terminology you&rsquo;d use to describe navigating an application in a web browser. Instead of scripting <code>get</code> and <code>post</code> requests sent and responses received, we&rsquo;re now speaking in terms of forms filled in and links clicked. The tests are more expressive in fewer lines of code than an equivalent integration test.</p>

<p>Under the default configuration, Rails system tests will run the application and tests in separate threads with the help of Capybara&rsquo;s <a href="https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings">Selenium</a> driver. During test execution, Selenium will open a separate browser window (by default, Chrome using <a href="https://sites.google.com/a/chromium.org/chromedriver/">ChromeDriver</a> installed separately) in which the tests will run. This is all preconfigured for you in the <code>test/application_system_test_case.rb</code> file that you see required at the top of the example system test above.</p>

<figure class='code'><figcaption><span>test/application_system_test_case.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ApplicationSystemTestCase</span> <span class="o">&lt;</span> <span class="ss">ActionDispatch</span><span class="p">:</span><span class="ss">:SystemTestCase</span>
</span><span class='line'>  <span class="n">driven_by</span> <span class="ss">:selenium</span><span class="p">,</span> <span class="ss">using</span><span class="p">:</span> <span class="ss">:chrome</span><span class="p">,</span> <span class="n">screen_size</span><span class="p">:</span> <span class="o">[</span><span class="mi">1400</span><span class="p">,</span> <span class="mi">1400</span><span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Rails supports other Capybara drivers as well, so we can swap out Selenium for another option using the same <code>driven_by</code> method. In some cases, configuring the driver may require an additional driver-specific setup block. See the READMEs for individual drivers for complete documentation. (In this case, for example, you see JS errors switched off because of problems with the <code>application.js</code> generated by Sprockets in this Rails release candidate.)</p>

<figure class='code'><figcaption><span>test/application_system_test_case.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'><span class="nb">require</span> <span class="s2">&quot;capybara/poltergeist&quot;</span>
</span><span class='line'><span class="nb">require</span> <span class="s2">&quot;capybara/webkit&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ApplicationSystemTestCase</span> <span class="o">&lt;</span> <span class="ss">ActionDispatch</span><span class="p">:</span><span class="ss">:SystemTestCase</span>
</span><span class='line'>  <span class="n">driven_by</span> <span class="ss">:selenium</span><span class="p">,</span> <span class="ss">using</span><span class="p">:</span> <span class="ss">:chrome</span><span class="p">,</span> <span class="n">screen_size</span><span class="p">:</span> <span class="o">[</span><span class="mi">1400</span><span class="p">,</span> <span class="mi">1400</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Rack::Test</span>
</span><span class='line'>  <span class="c1"># driven_by :rack_test</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># capybara-webkit</span>
</span><span class='line'>  <span class="c1"># Capybara::Webkit.configure do |config|</span>
</span><span class='line'>  <span class="c1">#   config.raise_javascript_errors = false</span>
</span><span class='line'>  <span class="c1"># end</span>
</span><span class='line'>  <span class="c1"># driven_by :webkit</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Poltergeist</span>
</span><span class='line'>  <span class="c1"># Capybara.register_driver :poltergeist do |app|</span>
</span><span class='line'>  <span class="c1">#   Capybara::Poltergeist::Driver.new(app, js_errors: false)</span>
</span><span class='line'>  <span class="c1"># end</span>
</span><span class='line'>  <span class="c1"># driven_by :poltergeist</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Each of the drivers has different characteristics and capabilities according to its implementation. <a href="https://github.com/rack-test/rack-test">Rack:Test</a> works a lot like Rails integration tests, and offers similar performance. Headless drivers like <a href="https://github.com/thoughtbot/capybara-webkit">capybara-webkit</a> and <a href="https://github.com/teampoltergeist/poltergeist">Poltergeist</a>offer a balance of JavaScript evaluation and acceptable performance. The table below summarizes the current driver options.</p>

<table class="results" style="width:100%">
  <colgroup>
    <col style="width:15%">
    <col style="width:20%">
    <col style="width:20%">
    <col style="width:20%">
  </colgroup>
  <tbody>
    <tr>
      <th></th>
      <th class="center">Rack::Test</th>
      <th class="center">Capybara::Webkit</th>
      <th class="center">Poltergeist</th>
      <th class="center">Selenium</th>
    </tr>
    <tr>
      <td class="right">Type</td>
      <td class="center">headless</td>
      <td class="center">headless</td>
      <td class="center">headless</td>
      <td class="center">browser-based</td>
    </tr>
    <tr>
      <td class="right">Concurrency</td>
      <td class="center">single-threaded</td>
      <td class="center">multithreaded</td>
      <td class="center">multithreaded</td>
      <td class="center">multithreaded</td>
    </tr>
    <tr>
      <td class="right">Speed</td>
      <td class="center">fast</td>
      <td class="center">not bad</td>
      <td class="center">not bad</td>
      <td class="center">pretty slow</td>
    </tr>
    <tr>
      <td class="right">Dependencies</td>
      <td class="center">none</td>
      <td class="center"><a href="https://trac.webkit.org/wiki/QtWebKit">QtWebKit</a></td>
      <td class="center"><a href="http://phantomjs.org/">PhantomJS</a></td>
      <td class="center"><a href="https://sites.google.com/a/chromium.org/chromedriver/">ChromeDriver</a></td>
    </tr>
    <tr>
      <td class="right">Script Eval</td>
      <td class="center">no</td>
      <td class="center">yes</td>
      <td class="center">yes</td>
      <td class="center">yes</td>
    </tr>
  </tbody>
</table>




<h2><img class="no-border left" src="http://chriskottom.com/images/but-wait-theres-more.png" title="But wait, there's more!" /></h2>


<p>Rails has followed a pretty consistent pattern of wrapping existing tools and layering on additional features and functionality that improve integration and ease of use, and that pattern continues. To that end, this initial implementation of system tests includes a couple of nice extended features that you should be aware of.</p>

<p>First, managing database access and consistency between Capybara and Rails has always been a chore. Because the test and the application often run in separate threads, they&rsquo;ve generally been unable to share state and transactions in the same way that other single-threaded Rails tests do. This removed the possibility of running tests within transactions that could be rolled back during the teardown and instead forced the use of <a href="https://github.com/DatabaseCleaner/database_cleaner">Database Cleaner</a> and other similar workarounds to return to a consistent state.</p>

<p>In this implementation, though, the application and test threads will share a single database connection between them, so they will operate within a single transaction and subsequently share a common view of the database - all out of the box.</p>

<p>Rails also generates screenshots for all failed and errored out system tests by default and tucks them into <code>tmp/screenshots</code>. This is a feature that&rsquo;s going to come in handy - especially for long-running tests and extra-especially as applications continue to move more logic to the client.</p>

<p>So far I&rsquo;m loving this combination of (no) setup and (more) features that system tests provide. If you&rsquo;ve read about my previous setup based on <a href="https://github.com/blowmage/minitest-rails-capybara">minitest-rails-capybara</a> in <a href="https://chriskottom.com/minitestcookbook/">The Minitest Cookbook</a>, let me be clear: this is my new jam, and I&rsquo;ll be shipping an update to the book sometime after Rails 5.1 officially ships that covers system tests.</p>

<p>Big ol&#8217; thanks to <a href="https://twitter.com/eileencodes">@eileencodes</a> for shepherding this feature into Rails. If you&rsquo;re interested in all the inside baseball about the development of this feature, you should really check out <a href="https://speakerdeck.com/eileencodes/building-the-new-rails-system-test-framework">the slides from her RailsConf talk</a>.</p>

<h2>Using System Tests: Need vs. Speed</h2>

<p><img class="no-border right" src="http://chriskottom.com/images/test-pyramid.png" width="400" title="The Test Pyramid" >
There was a time when acceptance tests like these were nice-to-have, but most applications are past that at this point. If you have any significant JS running on the client, anything that materially affects the DOM, then they&rsquo;re really must-have tests in your suite. All other things being equal, the more of your application that you can cover with system tests, the better.</p>

<p>Unfortunately, all things are not equal. System tests exercise more of the application and tend contain many more assertions than lower level tests, so they also tend to run slower. How much slower depends on your tests and the driver you&rsquo;re using, but they&rsquo;re usually slow enough that you&rsquo;ll probably want to think twice about running them all the time. But from what I&rsquo;ve seen so far, Rails provides some good defaults related to the new feature including:</p>

<ul>
<li>Runs system tests only when explicitly invoked with <code>rails test:system</code>, not as part of the default test task</li>
<li>Generates system tests by default, but allows opt-out with the <code>--skip-system-test</code> option on <code>rails new</code></li>
</ul>


<p>As a rule, I think it&rsquo;s a good policy to run unit-level tests (models, controllers, background jobs and helpers) often while you&rsquo;re working. Then, when you think you&rsquo;ve  got something ready to check in, run the entire test suite. Rails makes it easy to do that by passing a path to the test runner.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>chris@erdos:~/Projects/tiny_projects/blogg > rails test test/</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Versioning a Rails API]]></title>
    <link href="http://chriskottom.com/blog/2017/04/versioning-a-rails-api/"/>
    <updated>2017-04-05T11:03:26+02:00</updated>
    <id>http://chriskottom.com/blog/2017/04/versioning-a-rails-api</id>
    <content type="html"><![CDATA[<figure class="right" style="margin:10px 0 15px 15px">
  <img class="no-border" src="http://chriskottom.com/images/versioning-commitstrip.jpg" style="width:560px;margin:0">
  <figcaption style="text-align:center;margin-top:0px">
    <a href="http://www.commitstrip.com/en/2014/05/05/when-i-finally-manage-to-master-an-api-or-a-framework/">When I finally manage to master an API or framework</a><br>by <a href="http://www.commitstrip.com">CommitStrip.com</a>
  </figcaption>
</figure>


<p>API versioning is one of those topics that divides developers into two camps: those who just know that their way is the best way, and those that are confused by the first camp and would rather pass on the whole thing. Once we set aside the bikeshedding, there are sound, sane justifications for choosing one method over another, but in a lot of cases, discussions move from theoretical to hypothetical problems instead of worrying about making things that work.</p>

<p>The good news for Rails developers is that adding versions to an existing application doesn&rsquo;t have to be painful. If you know what to do, you can implement it and maintain it with little effort.</p>

<p>In this article, we&rsquo;ll look at what you get by versioning your API, why you need to think really hard before deciding not to, and how to update your application to make it work.<!--more--></p>

<h2>Hey, Is This <em>Really</em> Necessary?</h2>

<p>Short answer: probably. The purpose of versioning is to offer guarantees about your interface even as development continues. By not building those guarantees into your application, you&rsquo;re assuming personal responsibility for ensuring that client and server remain in lock step at all times. That&rsquo;s a difficult promise to keep in any of the following scenarios:</p>

<ul>
<li>You plan to introduce breaking changes in the future.</li>
<li>Any of your clients are installable software including desktop and mobile applications.</li>
<li>Third-party developers will be using your interface - with or without your support.</li>
</ul>


<p>Even in cases where the API is private and you control development and installation of both the clients and the server, versioning can mean being able to roll out changes gradually as they&rsquo;re ready and without as much orchestration required during deployment.</p>

<p>So yes, unless you&rsquo;re building a classic Rails monolith (client is JS sprinkles or deployed as an asset of the application) you probably do need to version your API. Just because it sucks, doesn&rsquo;t mean you can skip it if your app really needs it.</p>

<h2>Selecting an Interface Strategy</h2>

<p>Once you&rsquo;ve decided to version an API, you&rsquo;re essentially providing paths to access different representations of the same resource in parallel. So a request for version 1 of a given object might produce a very different response than version 6, even though the underlying state is the same. When we speak about RESTful APIs, we need a way for clients to specify which version of an endpoint is being requested, so that limits us to a relatively small set of possible options.</p>

<ul>
<li><strong>Hostname or subdomain:</strong> via multiple hostnames e.g. <code>v3.api.example.com</code></li>
<li><strong>URL segment:</strong> a version slug in the resource identifier, e.g. <code>/v1/users/100</code></li>
<li><strong>HTTP header:</strong> a custom header or MIME type parameter, e.g. <code>Accept: application/vnd.example.com; version=1</code></li>
<li><strong>Query parameter:</strong> via a query parameter, e.g. <code>/users/100?v=1</code></li>
</ul>


<p>Each of these methods has its advantages and disadvantages. Many consider using a request header, for example, as the most technically sound technique for a RESTful service since the URI for a given resource remains consistent regardless of the version. The most common method, though, and one that&rsquo;s certainly easier to test is probably using a version slug in the URL. That&rsquo;s the strategy we&rsquo;ll be using for the examples below, but understand that in all cases, the implementation will be similar in most respects.</p>

<h2>Implementing Multiple Versions</h2>

<p>A versioned API application needs to be partitioned so that it can render different resource representations based on the requested version. That&rsquo;s going to have an effect on any code involved in accepting HTTP requests and rendering responses, and in a prototypical Rails API application, that means the routes, controllers, and serializers as well as any tests that touch these. In contrast, models and other core application logic should specifically not be versioned in the same way. Any changes made to them over the lifetime of the application will generally need to be backward compatible. The diagram below gives a conceptual overview of how our example application will need to change.</p>

<p><img class="no-border center" src="http://chriskottom.com/images/versioning.png" width="700" title="Versioning a Rails API application" ></p>

<p>Suppose we have a really simple blogging application as an example with two resources: posts and comments.</p>

<figure class='code'><figcaption><span>config/routes.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">resources</span> <span class="ss">:posts</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">resources</span> <span class="ss">:comments</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>We can start on the path to versioning by updating the routes file to wrap the existing endpoints in a new namespace corresponding to version 1. The example below shows how to use a routing concern to cut down on duplication.</p>

<figure class='code'><figcaption><span>config/routes.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">concern</span> <span class="ss">:api_base</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">resources</span> <span class="ss">:posts</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">resources</span> <span class="ss">:comments</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">namespace</span> <span class="ss">:v1</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">concerns</span> <span class="ss">:api_base</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now we come to the job of refactoring the application so that it looks like the right-hand side of the diagram. We&rsquo;ll need to move and update source files to reflect the namespacing we just defined in the routes file. The changes we need to make are repetitive and mechanical, so if it helps, it&rsquo;s not a bad idea to begin by updating tests and letting them guide you through the remaining steps.</p>

<ul>
<li>Create <code>v1/</code> subfolders under <code>app/controllers</code>, <code>app/serializers</code>, <code>test/controllers</code>, and <code>test/serializers</code>.</li>
<li>Move the source files to be versioned under the new subfolders using <code>mv</code> or <code>git mv</code>.</li>
<li>Namespace the affected classes. Ex: <code>PostsController</code> becomes <code>V1::PostsController</code>.</li>
<li>Optionally, you can also create namespaced parent classes. Ex: <code>class V1::BaseSerializer &lt; ApplicationSerializer</code>.</li>
<li>Namespace test definitions with the correct versioned class name. Ex: <code>describe PostsController</code> becomes <code>describe V1::PostsController</code>.</li>
<li>Update routing URL helper methods to the new versioned names. Ex: <code>post_url</code> becomes <code>v1_post_url</code>.</li>
<li>Update resources interpreted as routes to use versioned URL helpers. Ex: <code>location: @post</code> becomes <code>location: v1_post_url(@post)</code>.</li>
</ul>


<p>It wasn&rsquo;t pretty, but you should now have version 1 of your API up and running. Creating a new version 2 that exists independently will follow much the same process. First, you&rsquo;ll define a new routing namespace similar to the one we created before.</p>

<figure class='code'><figcaption><span>config/routes.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">concern</span> <span class="ss">:api_base</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">resources</span> <span class="ss">:posts</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">resources</span> <span class="ss">:comments</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">namespace</span> <span class="ss">:v2</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">concerns</span> <span class="ss">:api_base</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">namespace</span> <span class="ss">:v1</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">concerns</span> <span class="ss">:api_base</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>And then you&rsquo;ll need to prepare the new versions of the source files to</p>

<ul>
<li>Recursively copy all the <code>v1/</code> source folders holding your controllers, serializers, and tests to <code>v2/</code> siblings.</li>
<li>Find and replace all instances of <code>v1|V1</code> in the new source files with <code>v2|V2</code>.</li>
</ul>


<p>This much copying and pasting of basically identical chunks of code should make you feel uneasy. As good codebase citizens, we&rsquo;d prefer to share functionality some other way - through inheritance, mixins, composition, anything but this. But bear in mind that each of these versions needs to stand on its own without the risk of changes to one affecting another. That&rsquo;s the reason for separating the endpoints and their tests through wholesale copying of code. And while I&rsquo;m still looking at Rails engines and other alternative methods of implementing versioning, this is the least-worst of the options I&rsquo;ve tried so far.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Get Up and Running with Rails API]]></title>
    <link href="http://chriskottom.com/blog/2017/02/get-up-and-running-with-rails-api/"/>
    <updated>2017-02-08T11:43:33+01:00</updated>
    <id>http://chriskottom.com/blog/2017/02/get-up-and-running-with-rails-api</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/ruby-plus-json.png" width="600" title="Ruby &hearts; JSON" >
The introduction of API-only applications in Rails 5 makes it easier than ever to write simplified apps that render JSON responses.  This is terrific news for those of us who&rsquo;ve spent years building up expertise in the platform, but as we already know, getting off on the right foot makes a big difference in how development proceeds.  This tutorial offers a quick overview of the first steps you&rsquo;ll use to get set up and coding on a typical Rails API application.<!--more--></p>

<h2>Generate the boilerplate application</h2>

<p>We can create a Rails API application just as we would any other Rails app - by using the generator to set up the folder structure with all the default files that we can then modify to suit our needs.  The only change is in the addition of the <code>--api</code> flag:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rails new my_new_app --api
</span></code></pre></td></tr></table></div></figure>


<p>This new application is a slimmed down version of the familiar structure we all know and love but with a few key differences:</p>

<ul>
<li>The base controller, ApplicationController, inherits from ActionController::API which doesn’t include some of the typical features controllers need when generating HTML - template rendering, cookies, sessions, flash, etc.</li>
<li>Everything related to the asset pipeline is missing - the app/assets folder, asset-related gems, etc.</li>
<li>Rails generators won&rsquo;t generate views, helpers or assets and will use templates more suitable for API apps for the files they do generate.</li>
</ul>


<p>In many cases, you can trim down the generated application even further by skipping other parts of the framework.  For example:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rails new my_new_app --api --skip-action-cable --skip-action-mailer
</span></code></pre></td></tr></table></div></figure>


<h2>Specify your dependencies</h2>

<p>Using Rails for API development means you have access to the same great developer experience and ecosystem of gems that are available for your server-generated HTML apps.  Even so, there are a few specific gems that I tend to add to every new API project right away.</p>

<ul>
<li><a href="https://github.com/rails-api/active_model_serializers">ActiveModel::Serializers</a> - standardize and simplify model object serialization</li>
<li><a href="https://github.com/cyu/rack-cors">Rack::Cors</a> - for serving client and server-side applications from different domains</li>
<li><a href="https://github.com/kickstarter/rack-attack">rack-attack</a> - request throttling, blacklisting and whitelisting</li>
</ul>


<p>I&rsquo;ve also been taking a look at <a href="https://github.com/nsarno/knock">Knock</a> for easy integration of JSON Web Tokens for authentication.</p>

<h2>Configure CORS</h2>

<p>If you&rsquo;re planning to serve your API and your client application from the same domain, setting up CORS right from the start might be overkill for you, but being able to host a client from S3 or to open your API up to selected developers, for example, can give you a lot of flexibility and room for growth in the future.  So I usually set this up right out of the gate.</p>

<p>Rails API applications include a commented out line in the <code>Gemfile</code> for the Rack::Cors middleware.  Just uncomment that and <code>bundle</code> to install the gem.</p>

<p>Your application will also include a sample initializer at <code>config/initializers/cors.rb</code>.  You’ll need to uncomment the lines there and configure CORS to handle requests from other valid origins.  For development, we might want to open up the application to serve requests from anywhere, but you may end up wanting to lock it down more tightly in production environments.  For that reason, I find it helpful to use an environment variable to specify the valid origins as in the sample code below.</p>

<figure class='code'><figcaption><span>config/initializers/cors.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">cors_origins</span> <span class="o">=</span> <span class="p">(</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;CORS_ORIGINS&#39;</span><span class="o">]</span> <span class="p">?</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;CORS_ORIGINS&#39;</span><span class="o">]</span><span class="p">)</span> <span class="p">:</span> <span class="s1">&#39;*&#39;</span> <span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">middleware</span><span class="o">.</span><span class="n">insert_before</span> <span class="mi">0</span><span class="p">,</span> <span class="ss">Rack</span><span class="p">:</span><span class="ss">:Cors</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">allow</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">origins</span> <span class="n">cors_origins</span>
</span><span class='line'>  <span class="n">resource</span> <span class="s1">&#39;*&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">headers</span><span class="p">:</span> <span class="ss">:any</span><span class="p">,</span>
</span><span class='line'>    <span class="nb">methods</span><span class="p">:</span> <span class="o">[</span><span class="ss">:get</span><span class="p">,</span> <span class="ss">:post</span><span class="p">,</span> <span class="ss">:put</span><span class="p">,</span> <span class="ss">:patch</span><span class="p">,</span> <span class="ss">:delete</span><span class="p">,</span> <span class="ss">:options</span><span class="p">,</span> <span class="ss">:head</span><span class="o">]</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>I usually use <a href="https://github.com/bkeepers/dotenv">dotenv</a> to manage environment variables in development and test, so in <code>.env</code> for development, I&rsquo;d have:</p>

<figure class='code'><figcaption><span>.env </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">CORS_ORIGINS</span><span class="o">=</span><span class="s1">&#39;.*&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<h2>When in doubt, use JSON:API</h2>

<p>Rails has always made it easy to develop web service endpoints as part or all of your application.  The difficult part has always been in answering the multitude of design decisions involved in each new project:</p>

<ul>
<li>What&rsquo;s the best way to represent the primary data in API responses?  How much should the client have to know about what it expects to receive?</li>
<li>How can you standardize the representation of server-side errors?</li>
<li>Is there a flexible, common way of including related data directly in the response?</li>
<li>What about links to the current request and related objects?</li>
<li>How should application-specific concerns be represented - ex: sorting, filtering, pagination, etc?</li>
<li>And so on&hellip;</li>
</ul>


<p>Starting every project by debating these questions from first principles is going to be counter-productive and frustrating, but fortunately, that&rsquo;s not necessary.</p>

<p><a href="http://jsonapi.org/">JSON:API</a> bills itself as &ldquo;the anti-bikeshedding tool&rdquo; for JSON-based APIs.  Essentially, it provides answers to all of the questions above and more as part of a single, evolving specification.  By adopting it, you get to avoid reinventing the wheel and all those lengthy discussions.</p>

<p>ActiveModel::Serializers, which you should install right from the start, bundles a JSON:API adapter, so setting up your Rails API application to conform to the standard is trivially easy.  Start by creating a new initializer to specify the JSON:API adapter:</p>

<figure class='code'><figcaption><span>config/initializers/active_model_serializers.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">adapter</span> <span class="o">=</span> <span class="ss">:json_api</span>
</span></code></pre></td></tr></table></div></figure>


<p>If you plan for any of your serializers to include links to the current or related resources, you&rsquo;ll also need to add a block of code to <code>config/environments/development.rb</code> and <code>config/environments/test.rb</code> that specifies the default URL options:</p>

<figure class='code'><figcaption><span>config/environments/development.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">configure</span> <span class="k">do</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Configure URL options for Rails helpers.</span>
</span><span class='line'>  <span class="n">config</span><span class="o">.</span><span class="n">after_initialize</span> <span class="k">do</span>
</span><span class='line'>    <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">default_url_options</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>      <span class="ss">host</span><span class="p">:</span> <span class="s1">&#39;localhost&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="ss">port</span><span class="p">:</span> <span class="s1">&#39;3000&#39;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The ActiveModel::Serializers repo includes <a href="https://github.com/rails-api/active_model_serializers/tree/master/docs">valuable documentation</a> on how to use the library and what to expect when using the JSON:API adapter.  These along with the <a href="http://jsonapi.org/format/">JSON:API spec</a> should be enough information to get most developers started and headed in the right direction.</p>

<h2>And the rest: déjà vu all over again&hellip;</h2>

<p>Most of the actual work of involved in delivering a Rails API application from this point forward is similar or identical to that of traditional server-rendered Rails apps.</p>

<ul>
<li>Domain modeling with Active Record or your favorite ORM</li>
<li>Business logic coding using POROs</li>
<li>Controller action development with Action Controller</li>
<li>Writing model and controller tests with Minitest or RSpec</li>
<li>Deployment to Heroku or with Capistrano</li>
<li>Consistent command line tooling and development environment</li>
</ul>


<p>All of these should look very familiar, even to novice Rails programmers with no prior web services experience, which is probably the single biggest advantage to using Rails for building APIs - that same great developer experience extended to a new kind of application.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[(Keep On) WebMockin' in the Real World]]></title>
    <link href="http://chriskottom.com/blog/2016/11/keep-on-webmockin-in-the-real-world/"/>
    <updated>2016-11-08T11:54:11+01:00</updated>
    <id>http://chriskottom.com/blog/2016/11/keep-on-webmockin-in-the-real-world</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/neil-young.png" width="600" title="Keep on rockin'" >
<a href="http://chriskottom.com/blog/2016/10/stubbing-external-apis-with-webmock/">In the last article</a>, I explained why it&rsquo;s a bad idea to test your Ruby code against real API endpoints and introduced <a href="https://github.com/bblimke/webmock">WebMock</a> as one option for stubbing out those integrations and keeping your tests speedy and manageable even as your suite grows.</p>

<p>That post used a really basic <a href="https://github.com/chriskottom/fivethirtyeight-tracker">example application</a> to show how to structure your tests under a simple use case.  But writing and testing distributed applications is rarely that simple, and most of the time, you&rsquo;ll find yourself needing to stub whole classes of requests and handle a number of common edge cases.  So using the patterns from last time as a baseline, let&rsquo;s now take a look at some other practical WebMock techniques to help you use it more effectively.<!--more--></p>

<h2>Constrain a Request Stub</h2>

<p>Basic stubbing of HTTP requests with WebMock can be pretty straightforward, as we saw last time:</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FiveThirtyEightHelpers</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">JSONFixtures</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">stub_summary_request</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>    <span class="n">status</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:status</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>    <span class="n">response_body</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:response_body</span><span class="p">,</span>
</span><span class='line'>                                  <span class="n">json_string</span><span class="p">(</span><span class="s2">&quot;fivethirtyeight_summary.json&quot;</span><span class="p">))</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">response_body</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This works just fine for simple cases like the one in that example application, but expect that sometimes you&rsquo;ll need to demonstrate that parameters are passed to the endpoint as expected.  That means checking the HTTP headers, query string, and request body.  Fortunately <code>WebMock::RequestStub</code> provides the <code>with</code> method that allows users to do just that.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># GET request with query Hash</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">query</span><span class="p">:</span> <span class="p">{</span> <span class="ss">q</span><span class="p">:</span> <span class="s1">&#39;chunky%20bacon&#39;</span> <span class="p">})</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">get_response_body</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># POST request with HTTP headers and body Hashes</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:post</span><span class="p">,</span> <span class="n">other_url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">headers</span><span class="p">:</span> <span class="p">{</span> <span class="s1">&#39;Content-Type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;application/json&#39;</span><span class="p">,</span>
</span><span class='line'>                  <span class="s1">&#39;User-Agent&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Faraday v0.9.2&#39;</span> <span class="p">},</span>
</span><span class='line'>       <span class="ss">body</span><span class="p">:</span> <span class="p">{</span> <span class="ss">animal</span><span class="p">:</span> <span class="s1">&#39;cartoon fox&#39;</span><span class="p">,</span> <span class="ss">vegetable</span><span class="p">:</span> <span class="s1">&#39;chunky bacon&#39;</span> <span class="p">})</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">post_response_body</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Request query and body Strings are parsed (regardless of encoding method - e.g. URL encoding, XML, JSON) and compared to any Hash instances passed via the <code>query</code> and <code>body</code> parameters.  WebMock will also accept Strings for these parameters, but in this case, keep in mind that parameter order matters.</p>

<p>In cases where you don&rsquo;t care about all of the parameters in the query string or request body, you can use the <code>hash_including</code> method to indicate a partial match:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># In the query string</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">query</span><span class="p">:</span> <span class="n">hash_including</span><span class="p">({</span> <span class="ss">q</span><span class="p">:</span> <span class="s1">&#39;chunky bacon&#39;</span><span class="p">,</span> <span class="ss">a</span><span class="p">:</span> <span class="s1">&#39;pet ham&#39;</span> <span class="p">}))</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">get_response_body</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># In the body</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:post</span><span class="p">,</span> <span class="n">other_url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">body</span><span class="p">:</span> <span class="n">hash_including</span><span class="p">({</span> <span class="ss">animal</span><span class="p">:</span> <span class="s1">&#39;cartoon fox&#39;</span> <span class="p">}))</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">post_response_body</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Generalize a Request Stub</h2>

<p>Some of the stub parameters can also be regular expressions in cases where we want stubs to respond to a wider range of requests:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># URL: matches both http/https, different domains</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="sr">/^https?:\/\/(www|staging|test)\.example\.com\//</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">get_response_body</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># Headers: send request with MSIE 6 user-agent</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">headers</span><span class="p">:</span> <span class="p">{</span> <span class="s1">&#39;User-Agent&#39;</span> <span class="o">=&gt;</span> <span class="sr">/compatible; MSIE 6\.0/</span> <span class="p">})</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">get_response_body</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># Body: ensure that the user&#39;s token is somewhere in the POST body</span>
</span><span class='line'><span class="n">stub_request</span><span class="p">(</span><span class="ss">:post</span><span class="p">,</span> <span class="n">post_url</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">with</span><span class="p">(</span><span class="ss">body</span><span class="p">:</span> <span class="sr">/token=</span><span class="si">#{</span> <span class="n">user_token</span> <span class="si">}</span><span class="sr">/</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>  <span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">post_response_body</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Stub an Error Response</h2>

<p>In addition to the usual &ldquo;happy path&rdquo;, integration code also needs to handle errors received from the external endpoint in a variety of common ways - e.g. propagating an exception, writing to a log file, printing to the screen, etc.  <a href="http://chriskottom.com/blog/2016/10/stubbing-external-apis-with-webmock/">In the previous post</a>, we showed how to make helper methods more flexible by allowing them to take a Hash of options including status code and response body.</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FiveThirtyEightHelpers</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">JSONFixtures</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">stub_summary_request</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>    <span class="n">status</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:status</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>    <span class="n">response_body</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:response_body</span><span class="p">,</span>
</span><span class='line'>                                  <span class="n">json_string</span><span class="p">(</span><span class="s2">&quot;fivethirtyeight_summary.json&quot;</span><span class="p">))</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">response_body</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>That design decision pays off right here.  Now we can use the same helper method that we used for the default scenario to produce an error response, and stubbing right at the point where the HTTP request is made keeps the focus of the test mainly on business-level functionality.</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">FiveThirtyEightHelpers</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">describe</span> <span class="s2">&quot;when the response has no body string&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">it</span> <span class="s2">&quot;raises an exception&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">stub_summary_request</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">404</span><span class="p">,</span> <span class="n">response_body</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="n">assert_raises</span><span class="p">(</span><span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:APIResponseError</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Simulate a Timeout</h2>

<p>Most HTTP clients provide a way of defining a timeout period for requests, and WebMock makes it easy to simulate a server timeout across all platforms and without the wait by immediately raising the appropriate error depending on the library in use.</p>

<figure class='code'><figcaption><span>test/support/fivethirtyeight_helpers.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FiveThirtyEightHelpers</span>
</span><span class='line'>  <span class="no">SUMMARY_URL</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">stub_summary_timeout</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="no">SUMMARY_URL</span><span class="p">)</span><span class="o">.</span><span class="n">to_timeout</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Like any other sort of error, you can choose how to handle these in your own application.  In this case, the example code catches the the low level timeout error and raises an application-specific error.</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">FiveThirtyEightHelpers</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">describe</span> <span class="s2">&quot;when the request times out&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">before</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">stub_summary_timeout</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">it</span> <span class="s2">&quot;raises an APITimeout&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_raises</span><span class="p">(</span><span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:APITimeout</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Verify a Stubbed Request</h2>

<p>Most of the time, APIs should deliver a meaningful response back to the client - something indicating the result of the request - but that&rsquo;s not always possible.  In some cases, processing is handed off to a background job, and the result might not be available when the response is generated.  In cases such as a logging service, the success or failure of individual requests might not be all that important.  And there are still other situations where a result is received but has no noticeable effect on the system under test - no new database records, no messages written to the log, etc.</p>

<p>In these cases, we still want to verify that the endpoint was called as expected, but what we need is closer to the <a href="http://martinfowler.com/articles/mocksArentStubs.html">classic definition of a mock object</a> than a stub.  We&rsquo;re checking that a collaborator (in this case, an external service) was called as expected, not that the object under test does the right thing with the result.  Fortunately for us, the <code>WebMock::RequestStub</code> returned by <code>stub_request</code> can be verified just like a regular mock object with the assertions WebMock provides.</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">FiveThirtyEightHelpers</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">describe</span> <span class="s2">&quot;when the API delivers a successful response&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">before</span> <span class="k">do</span>
</span><span class='line'>      <span class="vi">@api_stub</span> <span class="o">=</span> <span class="n">stub_summary_request</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">it</span> <span class="s2">&quot;requests data from the API&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>      <span class="n">assert_requested</span> <span class="vi">@api_stub</span>    <span class="c1"># opposite: #assert_not_requested</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Stubbing External APIs with WebMock]]></title>
    <link href="http://chriskottom.com/blog/2016/10/stubbing-external-apis-with-webmock/"/>
    <updated>2016-10-29T17:32:55+02:00</updated>
    <id>http://chriskottom.com/blog/2016/10/stubbing-external-apis-with-webmock</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/json-everywhere.jpg" width="450" title="JSON Everywhere" >
I&rsquo;ve recently been working on a number of projects that are built on multiple Rails applications, microservices, and data from third-party providers.  I can tell you one thing for sure: when your application is flinging JSON blobs all over the place, you can&rsquo;t use the same direct testing style that you would with a monolith.  Do so, and you create all sorts of problems for yourself including:</p>

<ul>
<li>Lousy test performance due to network overhead</li>
<li>Unexpected failures caused by connectivity issues, API rate limiting, and other problems</li>
<li>Undesired side effects from using a real web service (possibly even in the production environment)</li>
</ul>


<p>But the thornier problem is the lack of control you have when using live APIs for testing.  Working against a real system, it becomes a real trick to exercise your code against a full range of reasonable (and unreasonable) responses, so you find yourself stuck testing a few &ldquo;happy path&rdquo; scenarios and perhaps any cases that might happen to throw an exception from somewhere in the stack.<!--more--></p>

<h2>A Practical (and Mercifully Short-Term) Application</h2>

<p>So as an example (and with no small amount of fear and loathing) I wrote <a href="https://github.com/chriskottom/fivethirtyeight-tracker">a little program</a> that grabs the data feed from <a href="http://projects.fivethirtyeight.com/2016-election-forecast/">fivethirtyeight.com</a> and uses it to display a simple red and blue ASCII progress bar showing the current state of the race.</p>

<p><a target="_blank" href="http://chriskottom.com/images/fivethirtyeight_tracker.png"><img class="no-border center" src="http://chriskottom.com/images/fivethirtyeight_tracker.png" title="FiveThirtyEight Tracker"></a></p>

<p>The program includes <a href="https://github.com/chriskottom/fivethirtyeight-tracker/tree/master/lib/fivethirtyeight/feed.rb">a simple feed class</a> that fetches the latest forecast from the external service and pulls out the information we need.  The test for this class looks something like this:</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;delivers a simplified result set from the complete feed&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">forecast</span> <span class="o">=</span> <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:party</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;D&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:candidate</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;Clinton&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:probability</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="mi">80</span><span class="o">.</span><span class="mi">0</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>There&rsquo;s no way of knowing in advance what results the API will return on any given test run, so the odds that this test would ever pass are extremely low.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>&gt; rake
</span><span class='line'>Run options: --seed 5244
</span><span class='line'>
</span><span class='line'><span class="c"># Running:</span>
</span><span class='line'>
</span><span class='line'>F
</span><span class='line'>
</span><span class='line'>Finished in 0.886768s, 1.1277 runs/s, 3.3831 assertions/s.
</span><span class='line'>
</span><span class='line'>  1<span class="o">)</span> Failure:
</span><span class='line'>FiveThirtyEight::Feed#test_0001_delivers a simplified result <span class="nb">set </span>from the <span class="nb">complete </span>feed <span class="o">[</span>/home/ck1/Projects/fivethirtyeight_tracker/test/fivethirtyeight/feed_test.rb:11<span class="o">]</span>:
</span><span class='line'>Expected: 80.0
</span><span class='line'>  Actual: 82.16
</span><span class='line'>
</span><span class='line'>1 runs, 3 assertions, 1 failures, 0 errors, 0 skips
</span><span class='line'>rake aborted!
</span></code></pre></td></tr></table></div></figure>


<p>Ignoring the fact that this test fails, it took nearly <em>one whole second</em> to run with most of that time spent talking to the API.  As we add more tests will multiply the number of requests which will increase testing time linearly.  (Assuming, of course, that the provider doesn&rsquo;t get tired of the constant requests and simply block our IP.)</p>

<p>In short: we need to be able to test the application code isolated from the real API.</p>

<h2>WebMock to the Rescue</h2>

<p><a href="https://github.com/bblimke/webmock">WebMock</a> is a gem that integrates with all the major testing frameworks (including <a href="https://github.com/seattlerb/minitest">Minitest</a>, natch) and allows us to stub and set expectations on HTTP requests made during testing.  By stubbing network requests and responses several layers removed from our application code, we can inject canned responses with a degree of control we&rsquo;d never get using the API directly.</p>

<p>In the rest of this post, I&rsquo;ll describe how I&rsquo;ve used WebMock in my own tests to solve the problems described above, and I&rsquo;ll show how to organize your code to keep your tests clean and manageable.</p>

<h3>Step 1: Unplug from the Internet.</h3>

<p>Begin to isolate your tests by globally shutting down all HTTP requests.  Just include the <code>webmock</code> gem in your Gemfile, and add the following lines to your test helper:</p>

<figure class='code'><figcaption><span>test/test_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;webmock/minitest&#39;</span>
</span><span class='line'><span class="no">WebMock</span><span class="o">.</span><span class="n">disable_net_connect!</span>
</span></code></pre></td></tr></table></div></figure>


<p>WebMock includes stub adapters for Net::HTTP and most other popular HTTP libraries, so any test attempting to make an HTTP request will terminate with an error.</p>

<h3>Step 2: Stub individual requests.</h3>

<p>If we run tests now, we&rsquo;ll see that WebMock provides a helpful message with stub code we can use directly in our test.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>&gt; rake
</span><span class='line'>Run options: --seed 1257
</span><span class='line'>
</span><span class='line'><span class="c"># Running:</span>
</span><span class='line'>
</span><span class='line'>E
</span><span class='line'>
</span><span class='line'>Finished in 0.001997s, 500.7256 runs/s, 0.0000 assertions/s.
</span><span class='line'>
</span><span class='line'>  1<span class="o">)</span> Error:
</span><span class='line'>FiveThirtyEight::Feed#test_0001_delivers a simplified result <span class="nb">set </span>from the <span class="nb">complete </span>feed:
</span><span class='line'>WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: GET http://projects.fivethirtyeight.com/2016-election-forecast/summary.json with headers <span class="o">{</span><span class="s1">&#39;Accept&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;*/*&#39;</span>, <span class="s1">&#39;Accept-Encoding&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;gzip;q=1.0,deflate;q=0.6,identity;q=0.3&#39;</span>, <span class="s1">&#39;Host&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;projects.fivethirtyeight.com&#39;</span>, <span class="s1">&#39;User-Agent&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;Ruby&#39;</span><span class="o">}</span>
</span><span class='line'>
</span><span class='line'>You can stub this request with the following snippet:
</span><span class='line'>
</span><span class='line'>stub_request<span class="o">(</span>:get, <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span><span class="o">)</span>.
</span><span class='line'>  with<span class="o">(</span>:headers <span class="o">=</span>&gt; <span class="o">{</span><span class="s1">&#39;Accept&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;*/*&#39;</span>, <span class="s1">&#39;Accept-Encoding&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;gzip;q=1.0,deflate;q=0.6,identity;q=0.3&#39;</span>, <span class="s1">&#39;Host&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;projects.fivethirtyeight.com&#39;</span>, <span class="s1">&#39;User-Agent&#39;</span><span class="o">=</span>&gt;<span class="s1">&#39;Ruby&#39;</span><span class="o">})</span>.
</span><span class='line'>  to_return<span class="o">(</span>:status <span class="o">=</span>&gt; 200, :body <span class="o">=</span>&gt; <span class="s2">&quot;&quot;</span>, :headers <span class="o">=</span>&gt; <span class="o">{})</span>
</span><span class='line'>
</span><span class='line'>1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
</span></code></pre></td></tr></table></div></figure>


<p>Using this as a basis, we can now update the test and get it to pass.</p>

<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;delivers a simplified result set from the complete feed&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>    <span class="n">status</span> <span class="o">=</span> <span class="mi">200</span>
</span><span class='line'>    <span class="n">body</span> <span class="o">=</span> <span class="o">[</span>
</span><span class='line'>      <span class="p">{</span>
</span><span class='line'>        <span class="ss">state</span><span class="p">:</span> <span class="s2">&quot;US&quot;</span><span class="p">,</span>
</span><span class='line'>        <span class="ss">latest</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>          <span class="ss">D</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>            <span class="ss">party</span><span class="p">:</span> <span class="s2">&quot;D&quot;</span><span class="p">,</span>
</span><span class='line'>            <span class="ss">candidate</span><span class="p">:</span> <span class="s2">&quot;Clinton&quot;</span><span class="p">,</span>
</span><span class='line'>            <span class="ss">models</span><span class="p">:</span> <span class="p">{</span> <span class="ss">polls</span><span class="p">:</span> <span class="p">{</span> <span class="ss">winprob</span><span class="p">:</span> <span class="mi">80</span><span class="o">.</span><span class="mi">0</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="o">].</span><span class="n">to_json</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">to_return</span><span class="p">(</span><span class="ss">:status</span> <span class="o">=&gt;</span> <span class="n">status</span><span class="p">,</span> <span class="ss">:body</span> <span class="o">=&gt;</span> <span class="n">body</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">forecast</span> <span class="o">=</span> <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:party</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;D&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:candidate</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;Clinton&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:probability</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="mi">80</span><span class="o">.</span><span class="mi">0</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Step 3: Refactor.</h3>

<p>For a small application, we might just stop here, but for larger projects, it&rsquo;s a good idea to refactor and improve test readability before calling it a day.  To begin with, I&rsquo;ll extract the stub code to a helper method in a separate mixin.  This helps to declutter the test body and keeps the focus on the intent of the test, not the details of the request.  I usually write helper methods that take a Hash of options which provides some flexibility over essential variables like HTTP status code, query string, and response body.</p>

<figure class='code'><figcaption><span>test/support/fivethirtyeight_helpers.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FiveThirtyEightHelpers</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">stub_summary_request</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>    <span class="n">status</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:status</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>    <span class="n">response_body</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:response_body</span><span class="p">,</span> <span class="o">[</span>
</span><span class='line'>      <span class="p">{</span>
</span><span class='line'>        <span class="ss">state</span><span class="p">:</span> <span class="s2">&quot;US&quot;</span><span class="p">,</span>
</span><span class='line'>        <span class="ss">latest</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>          <span class="ss">D</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>            <span class="ss">party</span><span class="p">:</span> <span class="s2">&quot;D&quot;</span><span class="p">,</span>
</span><span class='line'>            <span class="ss">candidate</span><span class="p">:</span> <span class="s2">&quot;Clinton&quot;</span><span class="p">,</span>
</span><span class='line'>            <span class="ss">models</span><span class="p">:</span> <span class="p">{</span> <span class="ss">polls</span><span class="p">:</span> <span class="p">{</span> <span class="ss">winprob</span><span class="p">:</span> <span class="mi">80</span><span class="o">.</span><span class="mi">0</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="o">].</span><span class="n">to_json</span><span class="p">)</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">response_body</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Next, I like to extract the test data to a <a href="https://github.com/chriskottom/fivethirtyeight-tracker/tree/master/test/fixtures/json/fivethirtyeight_summary.json">fixture file</a> which I usually place under the <code>test/fixtures/json</code> directory.  It leaves the Ruby code cleaner still, and it ensures that we can load the data from within the test body if the need arises.  I&rsquo;ve written a number of helper methods that simplify access to the data as <a href="https://github.com/chriskottom/fivethirtyeight-tracker/tree/master/test/support/json_fixtures.rb">a module</a> which I can then include in any classes and modules that need it.</p>

<figure class='code'><figcaption><span>test/support/json_fixtures.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">JSONFixtures</span>
</span><span class='line'>  <span class="c1"># Return the path to the JSON fixtures directory</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">json_dir</span>
</span><span class='line'>    <span class="no">File</span><span class="o">.</span><span class="n">join</span> <span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">),</span> <span class="s2">&quot;../fixtures/json&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Return a filename for a JSON fixture</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">json_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span><span class='line'>    <span class="no">File</span><span class="o">.</span><span class="n">join</span> <span class="n">json_dir</span><span class="p">,</span> <span class="n">filename</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Return the contents of a JSON fixture as a String</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">json_string</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span><span class='line'>    <span class="no">File</span><span class="o">.</span><span class="n">read</span> <span class="n">json_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Return the contents of a JSON fixture as a data structure</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">json_struct</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span><span class='line'>    <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span> <span class="n">json_string</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can see for yourself how the API helper mixin and the test itself have benefited from the refactoring:</p>

<figure class='code'><figcaption><span>test/support/fivethirtyeight_helpers.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FiveThirtyEightHelpers</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">JSONFixtures</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">stub_summary_request</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;http://projects.fivethirtyeight.com/2016-election-forecast/summary.json&quot;</span>
</span><span class='line'>    <span class="n">status</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:status</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>    <span class="n">response_body</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="ss">:response_body</span><span class="p">,</span>
</span><span class='line'>                                  <span class="n">json_string</span><span class="p">(</span><span class="s2">&quot;fivethirtyeight_summary.json&quot;</span><span class="p">))</span>
</span><span class='line'>    <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">to_return</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">response_body</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>test/fivethirtyeight/feed_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">FiveThirtyEightHelpers</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:feed</span><span class="p">)</span> <span class="p">{</span> <span class="ss">FiveThirtyEight</span><span class="p">:</span><span class="ss">:Feed</span><span class="o">.</span><span class="n">new</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;delivers a simplified result set from the complete feed&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">stub_summary_request</span>
</span><span class='line'>    <span class="n">forecast</span> <span class="o">=</span> <span class="n">feed</span><span class="o">.</span><span class="n">current_forecast</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:party</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;D&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:candidate</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="s2">&quot;Clinton&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">forecast</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:D</span><span class="p">,</span> <span class="ss">:probability</span><span class="p">))</span><span class="o">.</span><span class="n">must_equal</span> <span class="mi">80</span><span class="o">.</span><span class="mi">0</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Running the tests one last time, the results show that we&rsquo;ve addressed both of the problems we set out to solve: the test passes, and the suite is hundreds of times faster than it was.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>&gt; rake
</span><span class='line'>Run options: --seed 49193
</span><span class='line'>
</span><span class='line'><span class="c"># Running:</span>
</span><span class='line'>
</span><span class='line'>.
</span><span class='line'>
</span><span class='line'>Finished in 0.003122s, 320.3415 runs/s, 1922.0488 assertions/s.
</span><span class='line'>
</span><span class='line'>1 runs, 6 assertions, 0 failures, 0 errors, 0 skips
</span></code></pre></td></tr></table></div></figure>


<h2>Limitations, Conditions, and Other Fine Print</h2>

<p>WebMock is a polished tool that solves a very narrow class of problems, but to use it effectively, you need to remain conscious of your objectives.  Specifically, you have zero control over the availability and responses delivered from the external service, so you cannot verify the behavior of your application as a whole.  Your request stubs represent a set of assumptions you&rsquo;ve made about the way the API works.  These assumptions already exist in your code, but you&rsquo;re now effectively copying them into your tests as well.  When the API changes or disappears, it&rsquo;s the responsibility of the developer to update those assumptions accordingly.</p>

<p>The FiveThirtyEight Tracker example makes this point perfectly.  As I&rsquo;m writing this, it&rsquo;s just a few days until election day, and I can reasonably expect that the API this code uses will disappear shortly thereafter.  My tests won&rsquo;t know that though, so if I&rsquo;m not careful, I could find myself in the confusing position of having green tests and a broken application.</p>

<p>If you&rsquo;d like to learn more about how to use WebMock in some practical cases, make sure to check out <a href="http://chriskottom.com/blog/2016/11/keep-on-webmockin-in-the-real-world/">part 2 of this series</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[User Stories Are Not Enough]]></title>
    <link href="http://chriskottom.com/blog/2016/09/user-stories-are-not-enough/"/>
    <updated>2016-09-30T10:05:54+02:00</updated>
    <id>http://chriskottom.com/blog/2016/09/user-stories-are-not-enough</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/agile-backlog.jpg" width="500" title="Scrum sprint backlog" >
As adoption of agile methodologies increases, more teams are finding user stories to be a useful tool for framing discussions with customers.  By defining features using simple, clear language and emphasizing the direct benefits to end users, project teams can organize and plan development activities in a way that&rsquo;s accessible to both business and technical stakeholders.</p>

<p>But like many other agile practices, much is lost between theory and application.  The original concept that drove the invention of user stories has been obscured with increaed popularity and wider adoption.  As a result, many development teams are trying to use the technique to solve problems it was never intended to address and seeing lackluster results.</p>

<p><strong>Understand this: user stories are not a lightweight substitute for traditional requirements management and documentation.</strong>  They&rsquo;re great when used as a high level outline of project features, but they&rsquo;re not a solution to every problem, and certainly not a replacement for a good specification.  By following an approach that includes user stories and selected, well-maintained documentation, development teams are able to better address a wider range of needs that every project will encounter.<!--more--></p>

<h2>Developers need more context, not less.</h2>

<p>User stories are limited by design - in scope and in detail.  Heck, the habit of writing them on physical index cards was originally a hack for enforcing brevity and preventing sprawl.  And when one of your priorities is to deliver new versions of working software at the end of each iteration, you want to make sure that developers have lots of manageably sized tasks to work on so you can show measurable progress all the time.</p>

<p>But projects need somewhere to think through and record long-term planning and big picture information.  When developers work without direct contact with users (which is more common than not) and are only focused on one feature at a time, they&rsquo;ll usually write code that&rsquo;s more brittle, ages poorly, and requires more maintenance over the long haul.  Providing them access to everything that&rsquo;s known about the features they&rsquo;re being asked to develop, they&rsquo;ll be better equipped to empathize with the user, engage their critical minds, ask follow-up questions, and ultimately build software more closely aligned with user needs.</p>

<h2>Design is both a noun and a verb.</h2>

<p>Back in the days of waterfall development, it was considered normal and responsible to block out anywhere from 20-40% of the schedule for requirements and design and produce copious documents that showed the work that had been done.  Upon completion, you&rsquo;d get everyone together in a conference room to agree that the documents accurately described <em>The Thing That Shall Be Built</em>, and from that point forward, everyone was locked into that plan.  Come hell or high water.</p>

<p>As you can imagine, the results that came out of this sort of Plan-Driven Development were not always awesome.  Eventually, a few smart people started taking notice and looking for ways to structure development projects differently.  Specifically, they noted that the requirements for these projects needed to be set and agreed at a point when the team had the least information about the target system - before implementation began.  Better would be an approach that let you go forth and build <em>The Thing That <u>Should</u> Be Built</em>, regardless of when you happened to figure out what that was.  Most teams practicing agile today have done away with <a href="http://c2.com/cgi/wiki?BigDesignUpFront">Big Design Up Front</a> and replaced it with a just-in-time approach - feature-driven, test-driven development that advances the application one bloody yard at a time.</p>

<p>Choosing between quite literally &ldquo;plan all the things&rdquo; or winging it is a false dichotomy, though.  Any non-trivial piece of software can realize benefits when someone takes the time to collect and write down some basic objectives and available information about it before coding.  It aligns the project team, but more importantly, the act of gathering requirements and producing a spec is proof that at least one person has thought deeply about what the system needs to do, what that implies, and how it might be achieved.  This isn&rsquo;t to say that everything written is true - always and forever, maybe not even ten minutes after it&rsquo;s written.  But the process here matters at least as much as the product.</p>

<p>This doesn&rsquo;t only pertain to the technical solution.  The same principles apply equally well to other aspects of the project that add value or help produce better outcomes.</p>

<ul>
<li>Wireframes and mockups</li>
<li>Front-end style guides</li>
<li>Process diagrams, flowcharts</li>
<li>Operations manuals, scaling plans</li>
</ul>


<p>Agile asks more of users than other software development approaches in that it really requires them to own their feature requests.  It shouldn&rsquo;t ask them to become experts, though, on all the other aspects of designing, building, and operating software.  That&rsquo;s our job, and we should take it seriously enough to write down what&rsquo;s important enough to remember about those areas.</p>

<h2>It&rsquo;s not just about you.</h2>

<p>Of all the various bits of software I&rsquo;ve worked on over the years, there are only a few that I&rsquo;m still working on today.  Many projects ended up as dropped bits or stashed in a directory on someone&rsquo;s hard disk, but there are several that are still doing their thing.  No one emails or calls about these systems anymore.  They&rsquo;re someone else&rsquo;s job now because I handed them off.</p>

<p>I like the term <em>knowledge transfer</em> for this situation because it covers all the possible scenarios where you&rsquo;ll need to dump what you know into someone else&rsquo;s head:</p>

<ul>
<li>The application is going live, and the support team needs enough info to handle tickets.</li>
<li>The business is being sold, and the new potential owners want to conduct a technical audit.</li>
<li>A new developer starts Monday, and she needs some basic materials to get acquainted with the system.</li>
</ul>


<p>User stories are a uniquely poor vehicle for this kind of knowledge. They are most useful within the context of a development iteration and rapidly lose value almost immediately thereafter.  Documentation, on the other hand, is less focused on cranking out code and more on the thing that was produced with the ability to organize it in a way that makes sense outside the context of the project.  But if you&rsquo;re practicing agile as most teams do, the set of documents available to bring new folks up to speed might be pretty thin indeed.</p>

<p><a href="http://martinfowler.com/bliki/AgileHandover.html">Martin Fowler has written about agile handovers on his blog</a>, and his take on the problem is very much at home in the agile playbook - establish cross-functional teams, transition only gradually, address knowledge transfer needs in a just-in-time fashion.  I&rsquo;ve never seen it work as cleanly as he describes it, but he is Martin Fowler, and Martin Fowler is way smarter than I&rsquo;ll ever be.  I&rsquo;ve seen acceptable results with a combination of written docs and in-person Q&amp;A sessions.</p>

<p>Developer onboarding is perhaps the most interesting situation of this type since it&rsquo;s a recurring event that occurs without much lead time.  Team leads need to be ready to bring someone up to speed at any time in much the same way that they should be able to deploy new releases of the system at any time.   Imagine the reaction from management you first needed <a href="https://kingsinsight.com/2011/02/10/agile-documentation-handover-to-production-support/">a bespoke strategy and implementation</a> before you could deploy a new version of an application.  Good luck with that.</p>

<h2>The Toughlove Conclusion</h2>

<p>A hammer is the perfect tool when you&rsquo;ve got a hammering job to do.  In other cases though, it&rsquo;s a poor fit at best and downright destructive at worst.  I think user stories are the same - a valuable technique during planning, outlining, estimation, and prioritization.  But they fall short as a way of organizing collected knowledge about the software to be built, and they&rsquo;re completely hopeless as an artifact of a system in operation.  For that, you need to fall back to more traditional, less fashionable approaches.</p>

<p><strong>Everyone wants the benefits of having written documentation without, you know, all the writing.</strong>  But keep in mind that the value of the documentation process is at least as great as that of the product.  To get the benefit, you need to be prepared to put in the work.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Next Decade of Programmer Productivity]]></title>
    <link href="http://chriskottom.com/blog/2016/09/the-next-decade-of-programmer-productivity/"/>
    <updated>2016-09-20T09:51:24+02:00</updated>
    <id>http://chriskottom.com/blog/2016/09/the-next-decade-of-programmer-productivity</id>
    <content type="html"><![CDATA[<p>Welcome to the future, coders.  We&rsquo;ve got large publishers and small businesses churning out books and running courses and bootcamps to produce armies of freshly minted coders.  Our text editors and tools write a lot of the code for us - at least the most tedious boilerplate code.  We have access to servers we can spin-up and spin-down for pennies an hour.  There are active communities of experts online 24 hours a day eager to answer any questions we might have along the way.  The support for people learning to code or wanting to improve has achieved a level of maturity that would have been unimaginable decades ago.</p>

<p>But while all this has been going on, we&rsquo;ve hit the wall in terms of our ability as an industry to solve real-world problems for consumers.  Improvements to hardware have allowed us add more window dressing to the systems we build, but what those systems are able to do remains mostly unchanged.  Software projects still routinely come in over-time and over-budget, <a href="https://hbr.org/2011/09/why-your-it-project-may-be-riskier-than-you-think">sometimes to an absurd degree</a>, and users and project sponsors are still routinely disappointed with the results they receive.  The root causes are at this point fairly well known.</p>

<ul>
<li>Unrealistic and poorly communicated objectives and schedules</li>
<li>Insufficient or absent requirements definition and management</li>
<li>Solutions that fail to solve users&#8217; most urgent problems</li>
<li>Underestimation due to lack of detailed planning, overconfidence, or management or peer pressure</li>
<li>Failure to identify and confront critical risk factors</li>
<li>Poor management oversight and visibility into the development process</li>
<li>Lack of end user involvement throughout the development process</li>
</ul>


<!--more-->


<h2>No Silver Bullet</h2>

<p>In his software engineering classic <em>The Mythical Man-Month</em>, Fred Brooks separates the problems that programmers face into two basic categories.  The <strong>essential problems</strong> of software are those which are inseparable from its function and include issues related to the conception and design of systems and managing them over time as requirements and the user environment changes.  The <strong>accidental problems</strong> are caused by the means and processes by which we represent the essence of the software - those things related to technologies, tools, processes, and so on.</p>

<p>Brooks predicted that the majority of improvements in productivity will come through addressing accidental issues, and in most respects, he&rsquo;s been proven right.  Advances in programming languages, development techniques, tooling, and development methodologies have removed a lot of the friction from the act of producing code.  In fact there are a lot of hassles in the daily work of programmers (see above) that we simply no longer consider, either because they&rsquo;ve been simplified to the point of being unworthy of notice or because they&rsquo;ve been automated so that we no longer have to deal with them at all.</p>

<p>But even as we continue to chip away at the accidental problems, the essential problems come to occupy an even larger part of the whole until we arrive at the point where we are now - that nearly all of the risks to our projects come from essential factors.  The friction in the process has been mostly stripped away exposing the fundamental issues beneath - how to manage complexity, change, and organizational factors.</p>

<p>The hard truth is that there&rsquo;s no Slack bot or Kanban board that&rsquo;s going to fix this.  Technological solutions will enable the change that has to take place, but we don&rsquo;t need new inventions or channels or apps to do what needs to be done.  <strong>The future of programmer productivity is in improving the quality and frequency of our communication.</strong></p>

<h2>A Communications Manifesto</h2>

<p>The Agile Manifesto began as a list of values shared by some of the best minds in software development.  That&rsquo;s how movements get started: as an idea put into words.  (You know, like communication!)  While there are many directions that this could go, here&rsquo;s a short list of what I&rsquo;ve seen work in the past.</p>

<ul>
<li>Faithfully communicate what you plan to do and what you have done, and leave behind a functional written record of both.</li>
<li>Curate a collection of great examples of technical writing, and model future communications on them.</li>
<li>Be direct during group discussions.  As a developer, you&rsquo;re often in the best position to see the problem with a given approach or requirement.</li>
<li>Standups, status updates, and other team checkpoints are critical for team cohesion and keeping everyone informed.  Don&rsquo;t treat them lightly, and don&rsquo;t make them optional.</li>
<li>Use retrospectives or a similar kind of meeting to find opportunities for improvement.</li>
<li>Assign mentors to new team members to ensure that team values are disseminated.</li>
<li>Communication problems can only be solved through conversations and team standards.  A tool is almost never the answer.</li>
<li>Regularly explain verbally what you&rsquo;ve done to end users and business stakeholders - in person if possible.</li>
<li>Speak regularly with business users about their work to understand it better.</li>
</ul>


<p>As with the Agile Manifesto, a declaration of values is only a first step.  The goal is to get others in the industry to think about how to communicate better and put these principles into action in their daily work.  But there&rsquo;s a big gap between recognizing the need and addressing it.  If we want to close this gap, we&rsquo;re going to need to put these values into action and let them permeate the instruments of our daily work.</p>

<ul>
<li>We need methodologies that systematize communication between developers and business units<sup>&dagger;</sup>.</li>
<li>We need educational resources disseminate these methodologies and to teach engineers to be better listeners and more effective verbal and written communicators.</li>
<li>We need tools that support and even require better communication within project teams.</li>
</ul>


<p>If we apply the same energy and enthusiasm to solving the essential problems of software development as we did to the accidental problems, we can expect to see even bigger improvements.</p>

<p><em><sup>&dagger;</sup> I know what you&rsquo;re thinking: Don&rsquo;t methodologies like Scrum include mechanisms for just this kind of communication?  Yes, that&rsquo;s true, but many teams only select the elements of agile workflows and leave those that they&rsquo;d rather skip.  The effect is that many teams&#8217; homegrown &ldquo;Scrum Lite&rdquo; frameworks include sprints and points and daily standups while leaving out the Product Owner role and many of the mandatory meetings.</em></p>

<h3>Further Reading &amp; Things to Think About</h3>

<ul>
<li><a href="https://www.oreilly.com/ideas/empathy-the-key-to-a-successful-software-project">Empathy: The key to a successful software project</a></li>
<li><a href="https://gettingreal.37signals.com/ch08_Wordsmiths.php">Wordsmiths</a></li>
<li><a href="http://blog.smartbear.com/management/10-reasons-development-teams-dont-communicate/">10 Reasons Development Teams Don’t Communicate</a></li>
<li><a href="http://paulgraham.com/makersschedule.html">Maker&rsquo;s Schedule, Manager&rsquo;s Schedule</a></li>
<li><a href="http://agilemanifesto.org/">Manifesto for Agile Software Development</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Key Takeaways from MicroConf Europe 2016]]></title>
    <link href="http://chriskottom.com/blog/2016/08/key-takeaways-from-microconf-europe-2016/"/>
    <updated>2016-08-12T07:20:12+02:00</updated>
    <id>http://chriskottom.com/blog/2016/08/key-takeaways-from-microconf-europe-2016</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/microconf-logo.png" title="MicroConf Europe" >
It&rsquo;s been about 10 days since I returned home from <a href="http://www.microconfeurope.com/">MicroConf Europe 2016</a>.  MicroConf is a special event for those in attendance - part industry event, part seminar, part summer camp, part support group.  And every year, I come away with a shopping list of tactics to try and tasks to be done AND the motivation to dig in and get started on them.  This year was no different.  Since getting back to my desk, I&rsquo;ve already:</p>

<ul>
<li>Collected relevant statistics my sales funnel since the beginning of 2016.</li>
<li>Filled in my content calendar for September and October.</li>
<li>Finished half of the book that was recommended to me by three different people.</li>
<li>Sketched out the broad strokes for two new projects.</li>
<li>Planned a head to head test to compare the two and decide which one to work on first later this year.</li>
</ul>


<p>Setting aside the tactical for a moment though, a lot the value of MicroConf comes from the larger lessons drawn from the talks and hallway conversations.  Sometimes, these are common threads that run through many interactions but never appear on a slide.  Now that I&rsquo;ve had some time for rest and recovery, I took some time this week to think through some of the broader themes from this year&rsquo;s conference.</p>

<p>(Special thanks to <a href="https://twitter.com/itengelhardt">Christoph Engelhardt</a>, the official MicroConf Europe scribe. Without his always great <a href="http://www.christophengelhardt.com/microconf-europe-2016-notes-noteworthy/">conference notes</a> to refer to, I wouldn&rsquo;t have been able to collect my thoughts nearly as easily.)<!--more--></p>

<h2>Kiss your comfort zone goodbye.</h2>

<p>A number of the speakers recalled times when they were forced to do things that were something more than what they&rsquo;d signed up for:</p>

<ul>
<li><a href="http://www.christophengelhardt.com/developer-ceo-peter-coppinger-microconf-europe-2016/">Peter Coppinger</a> used to lament the things that weren&rsquo;t happening in his business until one day he had a revelation - those things were the job the CEO, and that was him.  Since then, he&rsquo;s shifted his focus away from the coding that he loves to concentrate on building the company.</li>
<li><a href="http://www.christophengelhardt.com/two-years-saas-trenches-jordan-gal-microconf-europe-2016/">Jordan Gal</a> talked about acquiring his company&rsquo;s first customers by scanning the web for leads and plain, old cold emailing.  Pure hustle.</li>
<li><a href="http://www.christophengelhardt.com/building-optimizing-first-sales-process-steli-efti-microconf-europe-2016/">Steli Efti</a> put everyone in the room on notice that selling is not a super power.  No one likes being rejected, he just happens to have a little more practice at it than you do.</li>
</ul>


<p>Most founders starting businesses start off as practitioners with certain competencies and strengths.  That means that there will be a time in every business when something needs to be done, no one is quite sure how to do it, but they&rsquo;re all looking at you.  It might be sooner, it might be later, but it will happen.  And when it does, you can&rsquo;t put it off, you can&rsquo;t outsource it, you just need to roll up your sleeves and get it done.  Because if you signed up to be the founder, then doing the things that need doing <em>is</em> what you signed up for.</p>

<h2>If revenue is a rocket, profit is more like a 4&times;4.</h2>

<p>One thing that was very clear from many of the talks is that growing a software business is constant fire fighting.  There&rsquo;s no magic set of coefficients that when set up just right give you the magic formula for worry-free, sustained, ever-increasing profitability.  Up to a point, it&rsquo;s likely that the founders, possibly with the help of external contractors, can handle the work, but as the business grows, there are new challenges and tasks that need to be addressed.  Imagine this, for example:</p>

<ul>
<li>Congratulations, you added 50 new customers last month!</li>
<li>Wow, look at all the new support tickets.  You&rsquo;re going to need to hire someone to cut down on resolution times.</li>
<li>Oh noes, seems like all the tickets are being generated during onboarding.  You might want to hire a full-time success person to take ownership of that process.</li>
<li>Dammit, now you&rsquo;ve got employees, so you&rsquo;re going to need employment contracts (legal), health insurance (HR), better systems for running the team (managers), &hellip;</li>
<li>The new customers are really excited about the application, but now the system is slowing down.  You&rsquo;ll need to bump up the number of servers, too.</li>
</ul>


<p>You see where this is going.  Revenue is headed sharply up and to the right, but profitability is taking a much bumpier path as the new income is being eaten up to support a growing user base.</p>

<p>These are the growing pains that any business is going to experience when moving from childhood to adolescence.  The light at the end of the tunnel is that only some of these new expenses are going to grow in lock-step with revenue, so a SaaS business that reaches maturity should continue to benefit from the investments made during this growth phase.</p>

<h2>Put your trust in targets, not feelings.</h2>

<p>Two of the best talks at this year&rsquo;s conference were given by the organizers, <a href="http://www.christophengelhardt.com/drawing-lines-success-failure-mike-taber-microconf-europe-2016/">Mike Taber</a> and <a href="http://www.christophengelhardt.com/game-changers-rob-walling-microconf-europe-2016/">Rob Walling</a>.  Mike spoke about building and launching a product that, in spite of the time and effort he put into it, didn&rsquo;t find a market.  After he made the decision to kill the product, the experience led him to ask an important and valuable question: how do you know if you&rsquo;re failing?  He&rsquo;s now in the process of collecting information about self-funded product launches from builders and founders, and he talked about using &ldquo;guard rails&rdquo; - well-informed, predefined targets - to know whether the business that you&rsquo;re working on is on track or headed for the ditch.  He also outlined an approach that he used to select his next project which underscored the point about letting data make the decisions you don&rsquo;t trust yourself to make</p>

<p>Rob recently sold his email marketing automation company, <a href="https://www.getdrip.com/">Drip</a>, and in his talk, he reflected on the goals that have motivated him to acquire and build businesses over the years - freedom, purpose, relationships, and stability.  At various points along the way, he felt strong in some of those areas and weaker in others, and the talk was very candid about the kinds of stresses and struggles that this kinds of life can place on the founder and those close to him.</p>

<p>The common thread between these two very different talks was this: whether in your business or your life, it&rsquo;s easy to lose sight of the goal.  Your emotions can deceive you, especially when you&rsquo;re under stress, and how you feel from day to day isn&rsquo;t any indicator of progress.  You might be busting ass and maybe even making headway on short- and mid-term goals, and it might be taking you further away from where you want to be.  That&rsquo;s why it&rsquo;s crucial to decide early <strong>what will success look like when I get there</strong> and <strong>what do I expect to see along the way</strong>.  Write those things down somewhere, and refer to them periodically to make sure that all the work you&rsquo;re doing is having the desired effect.</p>

<h2>Until next time&hellip;</h2>

<p>Unlike so many technology-focused or big, heavily sponsored business conferences, MicroConf&rsquo;s secret sauce is the people you meet.  For a lot of the nerds in the house, three days of solid socializing can be exhausting, but for some of us, this is the one time of the year where we can sit down across the table from a stranger and talk about our ideas and struggles, successes and failures, without the need for prologue.  People just get you there.</p>

<p>This year, I had a chance to meet up with old friends and new ones, and I came away with stories, tips, hacks, book recommendations, feedback, criticism, and enough food for thought to feast on until next time.  Many thanks to <a href="https://twitter.com/andersthue">Anders</a>, <a href="https://twitter.com/benediktdeicke">Benedikt</a>, <a href="https://twitter.com/softwareverify">Stephen</a>, <a href="https://twitter.com/simplybastow">Janna</a>, <a href="https://twitter.com/ThomasSmale">Thomas</a>, <a href="https://twitter.com/katox">Kamil</a>, <a href="https://twitter.com/nosteve123">Steffen</a>, <a href="https://twitter.com/rwillmer">Rachel</a>, <a href="https://twitter.com/HathawayP">Patrick</a>, <a href="https://twitter.com/gareth_brown">Gareth</a>, <a href="https://twitter.com/silvioporcellan">Silvio</a>, <a href="https://twitter.com/dbader_org">Daniel</a>, and <a href="https://twitter.com/blukasz">Lukasz</a>.  And a special thanks to <a href="https://twitter.com/robwalling">Rob</a>, <a href="https://twitter.com/SingleFounder">Mike</a>, and <a href="https://twitter.com/Castro4Prsdnt">Xander</a> for putting together another great MicroConf.  I&rsquo;m already excited to see you all next year.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Minitest Cheat Sheet]]></title>
    <link href="http://chriskottom.com/blog/2016/08/minitest-cheat-sheet/"/>
    <updated>2016-08-10T16:28:59+02:00</updated>
    <id>http://chriskottom.com/blog/2016/08/minitest-cheat-sheet</id>
    <content type="html"><![CDATA[<p>Recently I came across a <a href="http://www.notmagic.org/minitest-dilemma">post</a> that called out a perceived lack of available documentation and other learning material for Minitest in contrast with RSpec.  And while I&rsquo;m not entirely sure I agree with the premise, the main point of the article had the ring of truth to it:</p>

<blockquote><p>If there&rsquo;s a problem to be solved here, it&rsquo;s that the obvious parts
of Minitest need to be better documented. Organize the new documentation
in the format of &ldquo;I want to do xyz thing&rdquo;,with an example.</p></blockquote>

<p>Honestly, what project couldn&rsquo;t use better docs - more focused, more examples, and detailed explanations?  That was exactly the same line of thinking that got me thinking about writing <a href="http://chriskottom.com/minitestcookbook">The Minitest Cookbook</a>.</p>

<p>I released a cheat sheet with the book that I thought might provide people with a partial solution, so I prepared a simplified version that includes a reference to the basic methods and syntax for Minitest and Minitest::Spec as well as a full listing of all assertions and expectations for each along with simple code examples for context.  (The full version also includes Rails-specific helpers and assertions and a list of the most commonly used Capybara methods.)<!--more--></p>

<p><a class="bigger" target="_blank" href="http://chriskottom.com/freebies/cheatsheets_free.pdf">Get the Cheat Sheet</a></p>

<p>Enjoy, and <a href="mailto:chris@chriskottom.com?subject=cheatsheet">let me know</a> if it helps you.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Testing Rails Background Workers]]></title>
    <link href="http://chriskottom.com/blog/2015/11/testing-rails-background-workers/"/>
    <updated>2015-11-24T07:27:32+01:00</updated>
    <id>http://chriskottom.com/blog/2015/11/testing-rails-background-workers</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/set_it_and_forget_it.png" title="Set it and forget it" >
When it was <a href="http://weblog.rubyonrails.org/2014/12/19/Rails-4-2-final/">released in Rails 4.2</a>, Active Job was an important addition to the platform.  Background jobs have been a part of the ecosystem for a long time, but this was the first time that developers had a single API to work with a variety of job queuing frameworks.  Having a common interface has led to a shared base of knowledge and patterns for developing and testing workers.</p>

<p><a href="http://chriskottom.com/blog/2015/11/bulletproof-rails-background-jobs/">In the last post, we looked at some good practices for writing well-designed background jobs in Rails using Active Job</a>, but we didn&rsquo;t get around to the question of how to test them.  This post will focus on a step-by-step strategy for testing all of your application&rsquo;s &ldquo;set it and forget it&rdquo; code - one that leverages the unified Active Job interface and the tools Rails and Minitest provide us.<!--more--></p>

<h2>Testing Your Business Logic</h2>

<p>In the last post, we said that moving business logic out of our background jobs and into plain old Ruby objects was a good way of future-proofing our applications.  As an example, we looked at a class that calculates the total score for a judge&rsquo;s evaluation from an app I&rsquo;ve been working on.</p>

<figure class='code'><figcaption><span>app/models/assessment_scorer.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">AssessmentScorer</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">score</span><span class="p">(</span><span class="n">assessments</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assessments</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">assessment</span><span class="o">|</span>
</span><span class='line'>      <span class="n">score</span> <span class="o">=</span> <span class="n">calculate_score</span><span class="p">(</span><span class="n">assessment</span><span class="p">)</span>
</span><span class='line'>      <span class="n">assessment</span><span class="o">.</span><span class="n">score</span> <span class="o">=</span> <span class="n">score</span> <span class="o">&amp;&amp;</span> <span class="n">assessment</span><span class="o">.</span><span class="n">save!</span>
</span><span class='line'>      <span class="k">yield</span> <span class="n">assessment</span><span class="p">,</span> <span class="n">score</span> <span class="k">if</span> <span class="nb">block_given?</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">calculate_score</span><span class="p">(</span><span class="n">assessment</span><span class="p">)</span>
</span><span class='line'>    <span class="c1"># ...</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>By extracting the domain-specific processing into its own class, we keep it from becoming entangled with the other work our application does - persistence, serving web requests, or in our case, background processing.  The resulting PORO is completely portable and can be used anywhere in the application where you need to calculate a score.  Because the interface is so basic, it&rsquo;s also dead simple to test.</p>

<figure class='code'><figcaption><span>test/models/assessment_scorer_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">AssessmentScorerTest</span> <span class="o">&lt;</span> <span class="ss">ActiveSupport</span><span class="p">:</span><span class="ss">:TestCase</span>
</span><span class='line'>  <span class="nb">test</span> <span class="s2">&quot;scores for assessments are set&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assessments</span> <span class="o">=</span> <span class="o">[</span><span class="n">assessments</span><span class="p">(</span><span class="ss">:good</span><span class="p">),</span> <span class="n">assessments</span><span class="p">(</span><span class="ss">:bad</span><span class="p">)</span><span class="o">]</span>
</span><span class='line'>    <span class="n">assessments</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">j</span><span class="o">|</span> <span class="n">assert_nil</span> <span class="n">j</span><span class="o">.</span><span class="n">score</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="no">AssessmentScorer</span><span class="o">.</span><span class="n">score</span><span class="p">(</span><span class="n">assessments</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="mi">46</span><span class="p">,</span> <span class="n">assessments</span><span class="p">(</span><span class="ss">:good</span><span class="p">)</span><span class="o">.</span><span class="n">reload</span><span class="o">.</span><span class="n">score</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="mi">24</span><span class="p">,</span> <span class="n">assessments</span><span class="p">(</span><span class="ss">:bad</span><span class="p">)</span><span class="o">.</span><span class="n">reload</span><span class="o">.</span><span class="n">score</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p><code>AssessmentScorer.score</code> has no meaningful return value, so we test it by making assertions about direct public side effects - in this case, that the score for each Assessment has been set to the expected value.</p>

<h2>Testing the Job</h2>

<p>As a rule of thumb, I try to keep my background workers lean and mean - 10-15 lines of code is usually plenty.  That&rsquo;s only possible by limiting what the job is allowed to do.  By removing all the business logic, you can reduce the <code>#perform</code> method to just a few basic responsibilities.</p>

<ul>
<li>Fetching models from the database</li>
<li>Handling exceptions raised during business logic execution</li>
<li>Retrying jobs, scheduling additional jobs, other follow-up actions</li>
</ul>


<p>In the previous post, you saw an example that followed these guidelines about extracting business logic but used the job itself to handle flow control.</p>

<figure class='code'><figcaption><span>app/jobs/process_imported_users_job.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ProcessImportedUsersJob</span> <span class="o">&lt;</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:Base</span>
</span><span class='line'>  <span class="n">queue_as</span> <span class="ss">:medium_priority</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">rescue_from</span> <span class="ss">ActiveRecord</span><span class="p">:</span><span class="ss">:RecordNotFound</span><span class="p">,</span> <span class="ss">CSV</span><span class="p">:</span><span class="ss">:MalformedCSVError</span> <span class="k">do</span> <span class="o">|</span><span class="n">error</span><span class="o">|</span>
</span><span class='line'>    <span class="no">UserImportsMailer</span><span class="o">.</span><span class="n">import_failed</span><span class="p">(</span><span class="vi">@import</span><span class="p">,</span> <span class="n">error</span><span class="p">)</span><span class="o">.</span><span class="n">deliver_now</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">perform</span><span class="p">(</span><span class="n">import_id</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@import</span> <span class="o">=</span> <span class="no">UserImport</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">import_id</span><span class="p">)</span>
</span><span class='line'>    <span class="n">csv</span> <span class="o">=</span> <span class="vi">@import</span><span class="o">.</span><span class="n">user_data</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">users</span><span class="p">,</span> <span class="n">errors</span> <span class="o">=</span> <span class="no">UserBulkLoader</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">csv</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span>
</span><span class='line'>      <span class="n">logger</span><span class="o">.</span><span class="n">debug</span> <span class="s2">&quot;Created new user account: </span><span class="si">#{</span> <span class="n">user</span><span class="o">.</span><span class="n">login</span> <span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="no">UserImportsMailer</span><span class="o">.</span><span class="n">import_completed</span><span class="p">(</span><span class="vi">@import</span><span class="p">,</span> <span class="n">users</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span><span class="o">.</span><span class="n">deliver_now</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>All the code for transforming the uploaded data into new user accounts has been refactored away to the UserBulkLoader class, so the worker is actually responsible for very little.  The test for the job can stay focused on two possible conditions: a successfully completed load and a rescued exception.</p>

<figure class='code'><figcaption><span>test/jobs/process_imported_users_job_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ProcessImportedUsersJobTest</span> <span class="o">&lt;</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:TestCase</span>
</span><span class='line'>  <span class="kp">include</span> <span class="ss">ActionMailer</span><span class="p">:</span><span class="ss">:TestHelper</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">setup</span> <span class="k">do</span>
</span><span class='line'>    <span class="vi">@import</span> <span class="o">=</span> <span class="n">user_imports</span><span class="p">(</span><span class="ss">:admin_import</span><span class="p">)</span>
</span><span class='line'>    <span class="ss">ActionMailer</span><span class="p">:</span><span class="ss">:Base</span><span class="o">.</span><span class="n">deliveries</span><span class="o">.</span><span class="n">clear</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s2">&quot;send a message upon completing an import&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">assert_no_emails</span>
</span><span class='line'>    <span class="no">ProcessImportedUsersJob</span><span class="o">.</span><span class="n">perform_now</span><span class="p">(</span><span class="vi">@import</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">assert_emails</span> <span class="mi">1</span>
</span><span class='line'>    <span class="n">message</span> <span class="o">=</span> <span class="ss">ActionMailer</span><span class="p">:</span><span class="ss">:Base</span><span class="o">.</span><span class="n">deliveries</span><span class="o">.</span><span class="n">last</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="o">[</span><span class="vi">@import</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">email</span><span class="o">]</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">to</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/Your User Import Task Has Completed/</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">subject</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>  <span class="nb">test</span> <span class="s2">&quot;a completely failing import job should notify the creator&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">kaboom</span> <span class="o">=</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span> <span class="k">raise</span> <span class="ss">ActiveRecord</span><span class="p">:</span><span class="ss">:RecordNotFound</span><span class="p">,</span> <span class="s2">&quot;Oh no!&quot;</span> <span class="p">}</span>
</span><span class='line'>    <span class="no">UserBulkLoader</span><span class="o">.</span><span class="n">stub</span><span class="p">(</span><span class="ss">:load</span><span class="p">,</span> <span class="n">kaboom</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="no">ProcessImportedUsersJob</span><span class="o">.</span><span class="n">perform_now</span><span class="p">(</span><span class="vi">@import</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">assert_emails</span> <span class="mi">1</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">message</span> <span class="o">=</span> <span class="ss">ActionMailer</span><span class="p">:</span><span class="ss">:Base</span><span class="o">.</span><span class="n">deliveries</span><span class="o">.</span><span class="n">last</span>
</span><span class='line'>    <span class="n">body</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">html_part</span><span class="o">.</span><span class="n">to_s</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/Your User Import Task Has Failed/</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">subject</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/ActiveRecord::RecordNotFound/</span><span class="p">,</span> <span class="n">body</span>
</span><span class='line'>    <span class="n">assert_match</span> <span class="sr">/Oh no\!/</span><span class="p">,</span> <span class="n">body</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Here we&rsquo;re using <code>perform_now</code> to execute the job immediately.  Since we&rsquo;re only interested in what happens inside the <code>#perform</code> method, we don&rsquo;t need to bother enqueuing an instance yet.</p>

<h2>Testing Job Queuing</h2>

<p>Background jobs are usually conditionally fired off from a model callback or a controller action.  In the case of this user import process, I chose to queue it from the controller action that handles new UserImport creation.</p>

<figure class='code'><figcaption><span>app/controllers/user_imports_controller.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">UserImportsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">create</span>
</span><span class='line'>    <span class="vi">@user_import</span> <span class="o">=</span> <span class="n">current_user</span><span class="o">.</span><span class="n">user_imports</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">user_import_params</span><span class="p">)</span>
</span><span class='line'>    <span class="n">authorize!</span> <span class="ss">:create</span><span class="p">,</span> <span class="vi">@user_import</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">respond_to</span> <span class="k">do</span> <span class="o">|</span><span class="nb">format</span><span class="o">|</span>
</span><span class='line'>      <span class="k">if</span> <span class="vi">@user_import</span><span class="o">.</span><span class="n">save</span>
</span><span class='line'>        <span class="no">ProcessImportedUsersJob</span><span class="o">.</span><span class="n">perform_later</span><span class="p">(</span><span class="vi">@user_import</span><span class="p">)</span>
</span><span class='line'>        <span class="nb">format</span><span class="o">.</span><span class="n">html</span> <span class="p">{</span> <span class="n">redirect_to</span> <span class="n">user_imports_path</span><span class="p">,</span> <span class="ss">notice</span><span class="p">:</span>
</span><span class='line'>          <span class="s1">&#39;User import was successfully created and is being processed.&#39;</span> <span class="p">}</span>
</span><span class='line'>      <span class="k">else</span>
</span><span class='line'>        <span class="nb">format</span><span class="o">.</span><span class="n">html</span> <span class="p">{</span> <span class="n">render</span> <span class="ss">:new</span> <span class="p">}</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>To test this, we&rsquo;ll want to demonstrate that the controller action queues a job when the new record is successfully saved and that it does nothing when the save fails.</p>

<figure class='code'><figcaption><span>test/controllers/user_imports_controller_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">UserImportsController</span><span class="p">,</span> <span class="s2">&quot;as administrator&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:TestHelper</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">before</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">sign_in</span> <span class="n">users</span><span class="p">(</span><span class="ss">:admin</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">describe</span> <span class="s2">&quot;#create&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">describe</span> <span class="s2">&quot;with valid parameters&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">it</span> <span class="s2">&quot;redirects to the imports list&quot;</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">assert_difference</span> <span class="s2">&quot;UserImport.count&quot;</span> <span class="k">do</span>
</span><span class='line'>          <span class="n">post</span> <span class="ss">:create</span><span class="p">,</span> <span class="n">user_import</span><span class="p">:</span> <span class="p">{</span> <span class="n">users_csv</span><span class="p">:</span> <span class="n">csv_attachment</span> <span class="p">}</span>
</span><span class='line'>        <span class="k">end</span>
</span><span class='line'>        <span class="n">assert_redirected_to</span> <span class="n">user_imports_path</span>
</span><span class='line'>        <span class="n">expect</span><span class="p">(</span><span class="n">flash</span><span class="o">[</span><span class="ss">:notice</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">must_equal</span> <span class="s1">&#39;User import was successfully created and is being processed.&#39;</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">it</span> <span class="s2">&quot;enqueues one job to process the import&quot;</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">assert_enqueued_with</span><span class="p">(</span><span class="ss">job</span><span class="p">:</span> <span class="no">ProcessImportedUsersJob</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>          <span class="n">post</span> <span class="ss">:create</span><span class="p">,</span> <span class="n">user_import</span><span class="p">:</span> <span class="p">{</span> <span class="n">users_csv</span><span class="p">:</span> <span class="n">csv_attachment</span> <span class="p">}</span>
</span><span class='line'>        <span class="k">end</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">describe</span> <span class="s2">&quot;with no file upload specified&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">it</span> <span class="s2">&quot;displays the new screen again&quot;</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">assert_no_enqueued_jobs</span> <span class="k">do</span>
</span><span class='line'>          <span class="n">post</span> <span class="ss">:create</span><span class="p">,</span> <span class="n">user_import</span><span class="p">:</span> <span class="p">{</span> <span class="n">users_csv</span><span class="p">:</span> <span class="s2">&quot;&quot;</span> <span class="p">}</span>
</span><span class='line'>        <span class="k">end</span>
</span><span class='line'>        <span class="n">assert_response</span> <span class="ss">:success</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>You need to include the <a href="http://api.rubyonrails.org/classes/ActiveJob/TestHelper.html">ActiveJob::TestHelper module</a> in your test case to gain access to the assertions and helper methods that needed to check which jobs have been queued or performed during the test.</p>

<p>Also, while Sidekiq is usually my Active Job backend of choice, I switch to the Rails-supplied test adapter for better control over job execution when running tests.  This is the default for all tests that subclass ActiveJob::TestCase, but I use it for all tests by including the following in my test helper.</p>

<figure class='code'><figcaption><span>test/test_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ActiveSupport</span><span class="o">::</span><span class="no">TestCase</span>
</span><span class='line'>  <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">active_job</span><span class="o">.</span><span class="n">queue_adapter</span> <span class="o">=</span> <span class="ss">:test</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Since Active Job provides a common interface for all supported queuing backends, we can swap in a different adapter with no changes to code or tests.</p>

<h2>Testing Your Application End-to-End</h2>

<p>Has this ever happened to you?  All the components of your application are fully covered with tests, but still, there are bugs creeping in - maybe even bugs that show up only in production or, worse, randomly.  Who hasn&rsquo;t been bitten by bugs in code that <em>seemed</em> well tested at every level?</p>

<p>Running background jobs solves one problem in your application but creates another by spreading the work across multiple processes.  Some classes of issues only show up in concurrent systems, and developers are historically really bad at isolating them.  One classic example is when the background job attempts to work with data that the main application thread hasn&rsquo;t committed to the database yet.</p>

<p>You&rsquo;ll have a better shot at detecting these types of defects in development using some sort of end-to-end tests.  I like acceptance testing with <a href="https://github.com/jnicklas/capybara">Capybara</a> and <a href="https://github.com/seattlerb/minitest">Minitest</a> for this kind of thing, as <a href="http://chriskottom.com/blog/2015/07/three-options-for-top-down-rails-testing/">I&rsquo;ve written about before</a>, but you can use whichever tools you prefer - just as long as they simulate the way real users will interact with your application.</p>

<figure class='code'><figcaption><span>test/features/can_upload_user_csv_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">feature</span> <span class="s2">&quot;Can Upload User CSV&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="kp">include</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:TestHelper</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span>     <span class="p">{</span> <span class="n">users</span><span class="p">(</span><span class="ss">:admin</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:csv_path</span><span class="p">)</span> <span class="p">{</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="p">,</span> <span class="s2">&quot;test/fixtures/files/users.csv&quot;</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">scenario</span> <span class="s2">&quot;upload a new batch of users&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">visit</span> <span class="n">root_path</span>
</span><span class='line'>    <span class="n">fill_in</span> <span class="s2">&quot;email&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">email</span>
</span><span class='line'>    <span class="n">fill_in</span> <span class="s2">&quot;password&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s2">&quot;password&quot;</span>
</span><span class='line'>    <span class="n">click_button</span> <span class="s2">&quot;Sign In&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">page</span><span class="p">)</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;Hi, Admin User!&quot;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">click_link</span> <span class="s2">&quot;Create New User Import&quot;</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">page</span><span class="p">)</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;New User Batch Upload&quot;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">assert_difference</span><span class="p">(</span><span class="s2">&quot;User.count&quot;</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_performed_with</span><span class="p">(</span><span class="ss">job</span><span class="p">:</span> <span class="no">ProcessImportedUsersJob</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">attach_file</span> <span class="s2">&quot;Users CSV File&quot;</span><span class="p">,</span> <span class="n">csv_path</span>
</span><span class='line'>        <span class="n">click_button</span> <span class="s2">&quot;Create User import&quot;</span>
</span><span class='line'>        <span class="n">expect</span><span class="p">(</span><span class="n">page</span><span class="p">)</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;User import was created and is being processed.&quot;</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The test above mimics an administrator logging into the application and uploading a CSV file with user data.  As we already mentioned, using the Active Job test adapter ensures that jobs aren&rsquo;t performed except when we explicitly permit it.  In this case, only the jobs queued within the <code>assert_performed_with</code> block will be executed, and we wrap that in a further <code>assert_difference</code> block to verify that the visible side effect - the creation of new user accounts - actually occurs.</p>

<p>Automated acceptance tests like this one won&rsquo;t guarantee that you find every possible integration bug, but they will improve your chances substantially over manual testing.  They also happen to be great at surfacing regressions after code changes and problems with displayed data or DOM manipulation by client-side scripts.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bulletproof Rails Background Jobs]]></title>
    <link href="http://chriskottom.com/blog/2015/11/bulletproof-rails-background-jobs/"/>
    <updated>2015-11-12T13:24:35+01:00</updated>
    <id>http://chriskottom.com/blog/2015/11/bulletproof-rails-background-jobs</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/bulletproof_superman.jpg">
The ability to run operations with long or uncertain execution times in the background has become a standard tool for modern web applications, and most frameworks and platforms now include some sort of support for encapsulating pieces of logic that involve heavy lifting out of the main request/response cycle.  For example, I recently finished work on a relatively simple Rails application that had about a dozen different background jobs written for a whole range of standard-ish use cases:</p>

<ul>
<li>Sending bulk notifications to a group of users</li>
<li>Consuming data from external APIs and updating the database</li>
<li>Batch creation of work items to users</li>
<li>Importing records from an uploaded data file</li>
<li>Complex object state manipulation that doesn&rsquo;t fit in an AR callback</li>
<li>Refreshing scores cached in the database after an admin changes the weights used to calculate them</li>
</ul>


<p>The way I write and test background workers has evolved over the years, and since I&rsquo;m getting ready to start a new project that will have a big background processing component, I thought it would be a good time to reflect on my approach and what I&rsquo;ve learned.<!--more--></p>

<p>Background processing libraries differ a little from one another in their semantics.  The examples in this post are written using Active Job and were backed by Sidekiq in the production environment, but For the purposes of this post, but most of the same patterns and principles can be applied generally regardless of the framework you choose.</p>

<h2>Separate Business Logic from Job Execution</h2>

<p><img class="no-border right" src="http://chriskottom.com/images/poro_all_the_things.jpg" title="PORO ALL THE THINGS!!" >
Rails developers, especially in the beginning, can get a little hung up on the One True Way of doing things and look to squeeze their applications into the buckets that Rails gives them - <code>assets</code>, <code>controllers</code>, <code>models</code>, and so on.  But if I had to give you one piece of advice for writing better background workers, it would be this: <strong>look for opportunities to pull bits of business logic out of your jobs and into plain-old Ruby objects</strong>.  As a rule, I&rsquo;d like to keep my job&rsquo;s <code>#perform</code> method as lean as possible - 10-15 lines of code is a good target.</p>

<p>Encapsulating most of the processing logic in POROs will usually help you achieve that goal while maintaining a nice <a href="http://deviq.com/separation-of-concerns/">separation of concerns</a> between logic that belongs to your business domain and logic associated with your queueing and retrying jobs.  Later, when you decide to switch background processing frameworks or want to move the processing to some other part of the application, you&rsquo;ll have a much easier time of it.</p>

<p>For example, one of my recent apps includes a scoring feature that lets users rate items on a 1-5 scale using various criteria.  The total score is computed based on the individual ratings and the weights assigned to each of the criteria which can be changed at any time by the administrator.  Ranking the items by their average scores might involve thousands of calculations, so the application caches the score calculated for each user&rsquo;s assessment to make the calculation easier and faster when displaying a table of leaders.  And I do this with a background job that leans heavily on a PORO.</p>

<figure class='code'><figcaption><span>app/models/assessment_scorer.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">AssessmentScorer</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">score</span><span class="p">(</span><span class="n">assessments</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assessments</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">assessment</span><span class="o">|</span>
</span><span class='line'>      <span class="n">score</span> <span class="o">=</span> <span class="n">calculate_score</span><span class="p">(</span><span class="n">assessment</span><span class="p">)</span>
</span><span class='line'>      <span class="n">assessment</span><span class="o">.</span><span class="n">score</span> <span class="o">=</span> <span class="n">score</span> <span class="o">&amp;&amp;</span> <span class="n">assessment</span><span class="o">.</span><span class="n">save!</span>
</span><span class='line'>      <span class="k">yield</span> <span class="n">assessment</span><span class="p">,</span> <span class="n">score</span> <span class="k">if</span> <span class="nb">block_given?</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">calculate_score</span><span class="p">(</span><span class="n">assessment</span><span class="p">)</span>
</span><span class='line'>    <span class="c1"># ...</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>app/jobs/recalculate_assessment_scores_job.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">RecalculateAssessmentScoresJob</span> <span class="o">&lt;</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:Base</span>
</span><span class='line'>  <span class="n">queue_as</span> <span class="ss">:medium_priority</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">perform</span><span class="p">(</span><span class="n">category_id</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assessments</span> <span class="o">=</span> <span class="no">Assessment</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">category_id</span><span class="p">:</span> <span class="n">category_id</span><span class="p">)</span>
</span><span class='line'>    <span class="no">AssessmentScorer</span><span class="o">.</span><span class="n">score</span><span class="p">(</span><span class="n">assessments</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">assessment</span><span class="p">,</span> <span class="n">score</span><span class="o">|</span>
</span><span class='line'>      <span class="n">logger</span><span class="o">.</span><span class="n">debug</span> <span class="s2">&quot;Scored assessment </span><span class="si">#{</span> <span class="n">assessment</span><span class="o">.</span><span class="n">id</span> <span class="si">}</span><span class="s2"> at </span><span class="si">#{</span> <span class="n">score</span> <span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>I like this pattern for a couple of different reasons.  First of all, the <code>#perform</code> method stays really simple - get the input parameters, fetch the necessary model objects, and delegate the important logic to something else.</p>

<p>Second, let&rsquo;s take a moment to appreciate the interface of this PORO.  It&rsquo;s clean, it&rsquo;s easy to understand, and I can pick it up and use it anywhere - in a controller action, as part of a Rake task, from the console, wherever.</p>

<p>You can also see that I&rsquo;m leaving open the option of passing a block to the logic in my PORO.  I tend to use this pattern a lot to inject logic that isn&rsquo;t strictly business-related but should be run sort of like a callback.  These are especially nice when you&rsquo;re processing a collection of objects as I am here.</p>

<h2>Let the Job Be Responsible for Flow Control</h2>

<p>Based on the previous example, you might be led to believe that the background job is nothing but a mechanism for executing the business logic asynchronously.  That&rsquo;s part of the picture, but more broadly, the job has a few responsibilities of its own:</p>

<ul>
<li>Handling input parameters</li>
<li>Delegating processing to models, service objects, etc.</li>
<li>Handling exceptions</li>
<li>Follow-up activities (retries, scheduling further jobs)</li>
</ul>


<p>In the same application, I wrote another job to handle bulk loading of user records based on a CSV file uploaded by the administrator.  Rather than forcing the user to wait for all the new records to be created, the controller just queued an import job to run in the background and rendered a response.  The job was then responsible for reporting back to the admin with the results of the import.</p>

<figure class='code'><figcaption><span>app/jobs/process_imported_users_job.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ProcessImportedUsersJob</span> <span class="o">&lt;</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:Base</span>
</span><span class='line'>  <span class="n">queue_as</span> <span class="ss">:medium_priority</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">perform</span><span class="p">(</span><span class="n">import_id</span><span class="p">)</span>
</span><span class='line'>    <span class="n">user_import</span> <span class="o">=</span> <span class="no">UserImport</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">import_id</span><span class="p">)</span>
</span><span class='line'>    <span class="n">csv</span> <span class="o">=</span> <span class="n">user_import</span><span class="o">.</span><span class="n">user_data</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">users</span><span class="p">,</span> <span class="n">errors</span> <span class="o">=</span> <span class="no">UserBulkLoader</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">csv</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span>
</span><span class='line'>      <span class="n">logger</span><span class="o">.</span><span class="n">debug</span> <span class="s2">&quot;Created new user account: </span><span class="si">#{</span> <span class="n">user</span><span class="o">.</span><span class="n">login</span> <span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="no">UserImportsMailer</span><span class="o">.</span><span class="n">import_completed</span><span class="p">(</span><span class="n">user_import</span><span class="p">,</span> <span class="n">users</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span><span class="o">.</span><span class="n">deliver_now</span>
</span><span class='line'>  <span class="k">rescue</span> <span class="ss">ActiveRecord</span><span class="p">:</span><span class="ss">:RecordNotFound</span><span class="p">,</span> <span class="ss">CSV</span><span class="p">:</span><span class="ss">:MalformedCSVError</span> <span class="o">=&gt;</span> <span class="n">e</span>
</span><span class='line'>    <span class="no">UserImportsMailer</span><span class="o">.</span><span class="n">import_failed</span><span class="p">(</span><span class="n">user_import</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span><span class="o">.</span><span class="n">deliver_now</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>In this case, the <code>#process</code> method is doing more than we saw in the previous example, but it sticks to the areas of responsibility that we outlined previously.</p>

<ul>
<li>Fetching the model that contains the CSV data to be imported based on the input parameter</li>
<li>Delegating responsibility for the actual bulk loading process to the UserBulkLoader class</li>
<li>Handling and logging the newly created records along with any errors</li>
<li>Sending an email after the job finishes notification with the results</li>
<li>Notifying the admin in case the job failed due to bad inputs</li>
</ul>


<p>In cases where we want to handle an exception by retrying the job, we can do that at the level of the class by including a <code>rescue_from</code> block like the one shown below.</p>

<figure class='code'><figcaption><span>app/jobs/process_imported_users_job.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ProcessImportedUsersJob</span> <span class="o">&lt;</span> <span class="ss">ActiveJob</span><span class="p">:</span><span class="ss">:Base</span>
</span><span class='line'>  <span class="n">queue_as</span> <span class="ss">:medium_priority</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">rescue_from</span><span class="p">(</span><span class="ss">ActiveRecord</span><span class="p">:</span><span class="ss">:ConnectionNotEstablished</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">retry_job</span> <span class="ss">wait</span><span class="p">:</span> <span class="mi">60</span><span class="o">.</span><span class="n">seconds</span><span class="p">,</span> <span class="ss">queue</span><span class="p">:</span> <span class="ss">:low_priority</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>As Rails applications have grown and matured, we&rsquo;ve asked them to do more complete and weighty tasks, and background jobs have been a necessity to keep the web application side of things responsive and zippy.  But in a lot of cases, developers simply dump code into workers and call it a day.  Just by following a few common-sense patterns, you can keep the back side of your code as neat and well-ordered as the front.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rails Got 99 Problems (But These Ain't Them)]]></title>
    <link href="http://chriskottom.com/blog/2015/09/rails-got-99-problems-but-these-aint-them/"/>
    <updated>2015-09-23T12:24:15+02:00</updated>
    <id>http://chriskottom.com/blog/2015/09/rails-got-99-problems-but-these-aint-them</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/trolling.jpg" width="400" title="Not sure if trolling or genuinely missed the point" ></p>

<p>I just finished reading Jared Friedman&rsquo;s <em><a href="http://blog.jaredfriedman.com/2015/09/15/why-i-wouldnt-use-rails-for-a-new-company/">Why I wouldn’t use rails for a new company</a></em>.  Mr. Friedman is the founding CTO of <a href="https://www.scribd.com/">Scribd</a> which means he&rsquo;s overseen the development of one of the biggest Rails-based applications on the web, and he&rsquo;s been notably ahead of the curve on important matters of technology (Scribd&rsquo;s transition from Flash to HTML5) and policy (SOPA).  In short, when he says something about building businesses on the back of Rails-based software, it&rsquo;s probably worth paying attention.</p>

<p>Which is probably why I found reading this article so frustrating.  I expected a well-informed argument combining technology- and business-oriented reasons that Rails was no longer where it&rsquo;s at, but what I got was a mixture of opinion and cherry-picked facts that were at best selective and at worst intentionally misleading.  It was a missed opportunity to <strong>have a serious discussion about the directions of Ruby and Rails as technologies and the factors that businesses should consider when deciding what tools to use when building out their applications</strong>.</p>

<p>I still like Rails for new application development - not just because of the time I&rsquo;ve spent learning the framework, but <strong>because I still believe Rails is a force multiplier for software development</strong>.  In this response to Mr. Friedman&rsquo;s piece, I want to examine the points he made in more detail, calling bullshit where necessary, and then add my two cents to the discussion by assessing what Rails does right and where it can still improve.<!--more--></p>

<h2>Argument 1: Ruby Is Slow</h2>

<p>Friedman points out that Ruby famously ranks poorly in language performance benchmarks and cites its status as a completely independent open source project with no deep-pocketed corporate backers investing money in speed improvements as the likely reason for it.</p>

<p>Ruby has gotten faster over time, but it&rsquo;s still pretty slow as programming languages go.  Compiled languages like Java and C++ are an order of magnitude faster than Ruby, and even other interpreted languages like Python routinely outperform Ruby.  Every Rails developer already knows this, and its pretty much as true now as it was back in the mid-2000s when Scribd founders decided to use it to build out their platform.</p>

<p>There are two reasons that this is a strange argument to lead off with though. First while website page load times do play a role in <a href="https://blog.kissmetrics.com/loading-time/">conversion rates</a>, <a href="http://googlewebmastercentral.blogspot.cz/2010/04/using-site-speed-in-web-search-ranking.html">search rankings</a>, and IT expenses, language performance in benchmarks is a mediocre indicator of page load time for web applications built using that language.  Other factors like the design of the development framework and the architecture of the application are both arguably much more important, and modern Rails applications use caching, background jobs, Ajax, and other techniques to deliver end-user performance that&rsquo;s at least sufficient for most applications and in the best cases competitive.  And if poor programming language performance were really prohibitive to building a successful business, then there would be no explanation for companies that manage to serve millions of visitors each month with Rails-based applications - Shopify, Airbnb, Bloomberg, GitHub, Basecamp, and so on.</p>

<p>But the second more important reason, and this really gets at the heart of Friedman&rsquo;s thesis, is that it&rsquo;s really rare that poor application performance sinks a business.  Businesses fail far more often for other reasons:</p>

<ul>
<li>Failing to identify a viable market for their product - or a viable product for their market</li>
<li>Inability to deliver a compelling solution to the identified problem</li>
<li>Lack of cash</li>
</ul>


<p>There are plenty of techniques and tactics that even moderately technically competent businesses can apply to solve performance problems, even if that involves throwing hardware at the problem.  But a fast application won&rsquo;t save a company that&rsquo;s failed to catch on with users.</p>

<h2>Argument 2: The Rails Framework Has Hit the Wall</h2>

<p>Friedman states that Rails was one of the first web development frameworks to focus extensively on the issue of programmer productivity, but despite this early lead, he says that it&rsquo;s lost ground to other frameworks that have adopted many of its innovations. The lack of new features, he says, have led many large applications to remain on older versions of the framework.</p>

<p>Rails has been steadily dropping new releases with important features all along. The record is clear and available to anyone willing to look.</p>

<ul>
<li>3.1 (August 2011) - Asset Pipeline, jQuery, CoffeeScript, Sass, reversible migrations,</li>
<li>3.2 (January 2012) - faster development mode, ARel explain queries</li>
<li>4.0 (June 2013) - Turbolinks, Russian Doll Caching</li>
<li>4.1 (April 2014) - Spring, Action Mailer previews, enums</li>
<li>4.2 (December 2014) - Active Job, asynchronous email delivery, web console</li>
</ul>


<p>Some features in that list have more fans than others, but it&rsquo;s not fair to say that the framework languished either.  (Friedman concedes later in the comments that Rails has evolved but has failed to meet the needs of larger companies, but he doesn&rsquo;t elaborate what these are or how they&rsquo;re different from the needs of smaller companies or the features that have actually been released.)</p>

<p>Friedman cites the fact that GitHub took years to upgrade its application to Rails 3 as evidence that new features just haven&rsquo;t been worth the pain of upgrading.  While I think that statement is probably true on the surface (<a href="http://shayfrendt.com/posts/upgrading-github-to-rails-3-with-zero-downtime/">albeit perhaps incomplete, based on indications from insiders</a>), the complications involved in upgrading an application with the scale of a GitHub or a Scribd is substantially greater than it would be for the typical Rails application and is only exacerbated by following a big-bang approach as opposed to keeping up with patches.</p>

<p>Friedman also contrasts the relatively minor tweaks in the Scribd server-side application with the big changes in the front-end which has &ldquo;gone from Prototype to jQuery to Coffeescript to Angular to React with major productivity improvements each time&rdquo;.</p>

<p>Wow&hellip;  That seems&hellip; scary.</p>

<p>The JavaScript landscape has seen more dramatic change than the Ruby back-end framework landscape, which has been dominated by Rails from the beginning, and I&rsquo;ll buy that React is a more productive tool than Prototype and probably more suited to a JavaScript-heavy site like Scribd.  <strong>But are we to understand that Scribd has written their front-end application five times since their founding?</strong>  Because that sounds completely monkey-balls to me as a developer and would seem like a big waste if I were someone with a stake in the business&#8217; bottom line.</p>

<h2>Argument 3: Rockstar Developers No Longer Interested</h2>

<p>Finally, Friedman says that Rails has suffered from a loss of buzz in recent years, especially among experienced developers, and that this is because of the masses of junior programmers being minted by bootcamps and code schools.  He also claims that the future belongs to newer, shinier technologies like Node.js and Go which are winning the battle for developer mindshare.</p>

<p>To support his claims, he first shows a graph reposted from <a href="http://codingvc.com/which-technologies-do-startups-use-an-exploration-of-angellist-data">an article</a> that shows technologies used by startups in the AngelList database.  Friedman says that the chart represents &ldquo;server languages&rdquo; and that it shows higher support for Node.js on the server side.  In fact though, the original article labels the chart as a comparison of &ldquo;programming languages&rdquo; only with no distinction made for client- or server-side technology.</p>

<p><img class="no-border center" src="http://chriskottom.com/images/angellist_languages.png" title="AngelList programming language popularity" ></p>

<p>Most modern web applications use at least some JavaScript, and JavaScript and CoffeeScript are now considered necessary tools for the complete Rails developer.  That being the case, the chart tells us nothing definitive about the Node vs. Rails battle on the server side.</p>

<p>Next, Friedman presents a comparison of job listing data from Indeed showing the frequency of different search terms which shows a massive surge for Node.js, a fact that indicates that the future belongs to Node thanks to its extraordinary growth curve.  (I&rsquo;ve removed some languages from the graph below for the sake of readability.)</p>

<div style="width:540px" class="center">
<a href="http://www.indeed.com/jobtrends?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js&relative=1&relative=1" title="php, ruby, rails, python, scala, node.js Job Trends">
<img width="540" height="300" src="http://www.indeed.com/trendgraph/jobgraph.png?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js&relative=1" border="0" alt="php, ruby, rails, python, scala, node.js Job Trends graph">
</a>
<table width="100%" cellpadding="6" cellspacing="0" border="0" style="font-size:80%"><tr>
<td><a href="http://www.indeed.com/jobtrends?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js&relative=1&relative=1">php, ruby, rails, python, scala, node.js Job Trends</a></td>
<td align="right"><a href="http://www.indeed.com/jobs?q=PHP">PHP jobs</a> - <a href="http://www.indeed.com/jobs?q=Ruby">Ruby jobs</a> - <a href="http://www.indeed.com/jobs?q=Rails">Rails jobs</a> - <a href="http://www.indeed.com/jobs?q=Python">Python jobs</a> - <a href="http://www.indeed.com/jobs?q=Scala">Scala jobs</a> - <a href="http://www.indeed.com/jobs?q=Node.js">Node.js jobs</a></td>
</tr></table>
</div>


<p>He fails to mention (except in a later comment) that the numbers are relative - Indeed doesn&rsquo;t actually say how we should interpret the graph - and that they don&rsquo;t reflect current jobs offered.  That would look more like this.</p>

<div style="width:540px" class="center">
<a href="http://www.indeed.com/jobtrends?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js" title="php, ruby, rails, python, scala, node.js Job Trends">
<img width="540" height="300" src="http://www.indeed.com/trendgraph/jobgraph.png?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js" border="0" alt="php, ruby, rails, python, scala, node.js Job Trends graph">
</a>
<table width="100%" cellpadding="6" cellspacing="0" border="0" style="font-size:80%"><tr>
<td><a href="http://www.indeed.com/jobtrends?q=php%2C+ruby%2C+rails%2C+python%2C+scala%2C+node.js">php, ruby, rails, python, scala, node.js Job Trends</a></td>
<td align="right"><a href="http://www.indeed.com/jobs?q=PHP">PHP jobs</a> - <a href="http://www.indeed.com/jobs?q=Ruby">Ruby jobs</a> - <a href="http://www.indeed.com/jobs?q=Rails">Rails jobs</a> - <a href="http://www.indeed.com/jobs?q=Python">Python jobs</a> - <a href="http://www.indeed.com/jobs?q=Scala">Scala jobs</a> - <a href="http://www.indeed.com/jobs?q=Node.js">Node.js jobs</a></td>
</tr></table>
</div>


<p>To read these numbers, you&rsquo;d have to conclude that Python is the way to go, but chasing trends and the new thing is only valuable if you&rsquo;re able to monetize novelty.  If your business is software, novelty isn&rsquo;t going to make your developers more productive or your technology more reliable.  Most trends come and go, a few come and stick around, but choosing a technology to base your business on strictly by looking at the new hotness is going to produce more losers than winners because winners are hard to pick in every market.  As a technology manager, you need to select technologies based on the risks involved and how well suited it is to your business needs - not a snapshot of what&rsquo;s trendy this week.</p>

<p>When I think about the question of a large population of bootcamp graduates entering the community and the workforce, my outlook isn&rsquo;t nearly as grim as Friedman&rsquo;s seems to be.  I remember similar discussions about junior Java developers - some self-taught from books like &ldquo;Learn Java in 30 Days&rdquo;, some graduating from certificate programs - back in the late 1990s, but Java remained and remains a viable technology even today.  The reality is that any serious development project, regardless of the tools used, is going to have a mix of tasks that need to be done - lots and lots of menial chores that simply need to be churned out along with a much smaller number of big, hard problems to be solved.  There will always be a place for the elite coders and architects to do the kind of work that juniors simply don&rsquo;t have the expertise to do, and the less experienced developers benefit from proximity to such work.  This is where &ldquo;serious programmers&rdquo; come from.</p>

<h2>Seeing Clearly, Minus the Ruby-Colored Glasses</h2>

<p><img class="no-border right" src="http://chriskottom.com/images/anti-hate-shields.gif" width="500" title="Activate the anti-hate-shields!" ></p>

<p>Mr. Friedman&rsquo;s criticism is shallow and poorly researched, but I&rsquo;m willing to concede my own bias.  <strong>I still see Rails as a cheat code for building web-based applications.</strong>  The total package that it provides out of the box - a well-structured application, effortless persistence, modern asset packaging, support for background jobs, steadily improving performance, and many other features - is hard to beat.</p>

<p>That said though, there are still big issues that need to be ironed out in order to improve Ruby on Rails as a development and deployment platform - just not the ones that Friedman thinks:</p>

<ul>
<li>The Ruby interpreter supports parallel execution only with multiple processes - a serious consideration when building large, multi-user applications for web and mobile.  (The JRuby and Rubinius interpreters don&rsquo;t have the same limitation.)</li>
<li>A lot of well-respected developers have very publicly called out the patterns embedded in Rails, especially in its handling of model objects and persistence.</li>
<li>Rails application architectures are usually relatively uniform and standardized with respect to the framework but often variable when it comes to areas not addressed by the framework.</li>
<li>Tooling for Ruby and Rails development is still very immature compared to other languages and frameworks.</li>
<li>The deployment story for Rails applications remains a work in progress with many different tools and operational models in use.</li>
<li>Maintaining a Rails application over the long term with a larger team requires an investment of time and money to maintain high coding standards, though it&rsquo;s not clear that this is a shortcoming of either the language or the framework.</li>
</ul>


<p>None of these is a showstopper when it comes to building a viable business, but they&rsquo;re all technical problems that I think are more cause for concern than those mentioned above.</p>

<p>More important to understand, though, is that <strong>problems are a sign of life</strong>.  In 2015, Rails serves a massive community, and the fact that there&rsquo;s still so much discussion about how the framework could improve and grow is a sign that developers still care and that Rails still matters.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Three Options for Top-Down Rails Testing]]></title>
    <link href="http://chriskottom.com/blog/2015/07/three-options-for-top-down-rails-testing/"/>
    <updated>2015-07-23T11:22:16+02:00</updated>
    <id>http://chriskottom.com/blog/2015/07/three-options-for-top-down-rails-testing</id>
    <content type="html"><![CDATA[<p>The most popular methods for learning Ruby on Rails today all place testing front and center.  <a href="https://www.railstutorial.org/">The Ruby on Rails Tutorial</a> incorporates sections on testing in almost every chapter as does <a href="https://pragprog.com/book/rails4/agile-web-development-with-rails-4">Agile Web Development with Rails 4</a>.  <a href="http://www.amazon.com/Rails-Edition-Addison-Wesley-Professional-Series/dp/0321944275">Other popular Rails books</a> concentrate most of their testing material in one or two chapters, but I don&rsquo;t know of any important teaching resource that ignores it entirely.</p>

<p>But even though a culture of testing runs deep within the community and is the modus operandi in most large Rails shops, certain essential concepts that remain elusive to many.  Take the differences between the types of tests usually found in Rails applications as an example.  Most programmers can clearly explain the differences between model and controller tests, but ask about controller tests versus integration tests, and you&rsquo;ll probably get a mixture of confusion and shrugs.<!--more--></p>

<p>Given <a href="http://chriskottom.com/blog/2015/07/ruby-and-rails-testing-changes-roundup/">recent changes</a> to controller tests and the ways that Rails apps themselves are changing, testing higher in the application stack is becoming more important than before.  In this post, I&rsquo;ll outline three different types of automated tests that Rails developers can use to exercise their applications&#8217; upper layers.  I&rsquo;ll explain the differences between these types of tests, outline the situations when each can and should be used, and finally share with you the scheme that I use when testing my own applications.</p>

<h3>Controller Tests</h3>

<p>Controller tests are well understood because they are standard Rails tests and are pretty much what they sound like - tests to exercise your controller classes - though you might hear some Rails old-timers referring to them by their former name: functional tests.  The new terminology is less ambiguous though, and so it&rsquo;s a better fit for what these tests are and do.</p>

<p>Every controller test case file maps to a single Rails controller, and every test method exercises a single scenario for a specific action.  Suppose we have an application with a <code>UserSessionsController</code> class that includes a login action for authentication.  By default, Rails places a <code>UserSessionsControllerTest</code> file in <code>test/controllers</code> when the boilerplate controller is generated, and to that, we can add test methods for:</p>

<ul>
<li>Logging in with a good username and password</li>
<li>Logging in with a bad username</li>
<li>Logging in when already logged in</li>
</ul>


<p>In each case, we want to maintain control over the pre-test state of the application and the inputs passed to the controller action when the test is executed.  That might include request parameters, cookies, session variables, and request headers as well as the usual model objects.  Like other tests though, we&rsquo;ll need to make assertions on only the <em>outputs</em> sent back to the client in the form of the HTTP response and the <em>observable side effects</em> produced by the action.</p>

<table class="results">
  <col style="width: 30%">
  <col style="width: 30%">
  <thead>
    <tr class="header">
      <th>HTTP Response</th>
      <th>Side Effects</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="center" valign="top">
        HTTP status code
        <br/>
        Redirect location
        <br/>
        Cookies set
      </td>
      <td class="center" valign="top">
        Rails flash values
        <br/>
        Session variable values
        <br/>
        Model changes
        <br/>
        Mail messages sent
        <br/>
        Jobs enqueued / performed
      </td>
    </tr>
  </tbody>
</table>


<p>To the extent that there&rsquo;s been any confusion over the role of these tests in recent years, it might be attributed to changes made by Rails core.  These include:</p>

<ul>
<li>Controller tests used to include assertions for validating the markup generated when the tested action ran - e.g. <code>assert_select</code> and other related methods.  These were extracted to a <a href="https://github.com/rails/rails-dom-testing">separate gem</a> (not deprecated completely, as pointed out by @aar0nr) some time ago.</li>
<li>Rails 5 will also see the <a href="https://github.com/rails/rails/issues/18950">deprecation of two other common testing methods</a> - <code>assert_template</code>, for determining whether or not a given template or partial is rendered, and <code>assigns</code>, which supplies the value of a controller instance variable.</li>
</ul>


<p>Speaking as someone who had plenty of legacy code bases, these changes were unpleasant surprises at the time, but the resulting controller test scope of responsibility is tighter and leaner now that it focuses on HTTP responses and side effects.  But then that forces us to ask: how should we test the application as a whole?  The right answer will depend on how your app is built.</p>

<h3>Integration Tests</h3>

<p>Rails integration tests closely resemble controller tests at the API level, but because they feed simulated HTTP requests to the <a href="http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack">Rails Dispatcher</a> rather than through the controller, they&rsquo;re able to simulate complex interactions utilizing more of the application stack.  Each request takes place within the context of a user session, and a single integration test can open any number of sessions as you can see in the example below.</p>

<figure class='code'><figcaption><span>test/integration/shopper_interactions_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ShopperInteractionsTest</span> <span class="o">&lt;</span> <span class="ss">ActionDispatch</span><span class="p">:</span><span class="ss">:IntegrationTest</span>
</span><span class='line'>  <span class="nb">test</span> <span class="s2">&quot;place order and check orders admin&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">shopper</span> <span class="o">=</span> <span class="n">login_as</span> <span class="n">users</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span>
</span><span class='line'>    <span class="n">admin</span> <span class="o">=</span> <span class="n">login_as</span> <span class="n">users</span><span class="p">(</span><span class="ss">:administrator</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">product</span> <span class="o">=</span> <span class="n">products</span><span class="p">(</span><span class="ss">:rails_book</span><span class="p">)</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">post</span> <span class="n">line_items_path</span><span class="p">,</span> <span class="n">line_item</span><span class="p">:</span> <span class="p">{</span> <span class="n">product_id</span><span class="p">:</span> <span class="n">product</span><span class="o">.</span><span class="n">id</span> <span class="p">}</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">follow_redirect!</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">root_path</span><span class="p">,</span> <span class="n">shopper</span><span class="o">.</span><span class="n">path</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">order_params</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>      <span class="nb">name</span><span class="p">:</span> <span class="s2">&quot;Chris Kottom&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="ss">address</span><span class="p">:</span> <span class="s2">&quot;My house&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="ss">email</span><span class="p">:</span> <span class="s2">&quot;chris@example.com&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="n">pay_type</span><span class="p">:</span> <span class="s2">&quot;Credit Card&quot;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="n">assert_difference</span> <span class="s2">&quot;Order.count&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">shopper</span><span class="o">.</span><span class="n">post</span> <span class="n">orders_path</span><span class="p">,</span> <span class="ss">order</span><span class="p">:</span> <span class="n">order_params</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">follow_redirect!</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">root_path</span><span class="p">,</span> <span class="n">shopper</span><span class="o">.</span><span class="n">path</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">order</span> <span class="o">=</span> <span class="no">Order</span><span class="o">.</span><span class="n">last</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">get</span> <span class="n">orders_path</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">assert_select</span> <span class="s2">&quot;#orders #order_</span><span class="si">#{</span> <span class="n">order</span><span class="o">.</span><span class="n">id</span> <span class="si">}</span><span class="s2">&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">admin</span><span class="o">.</span><span class="n">assert_select</span> <span class="s2">&quot;a[href=?]&quot;</span><span class="p">,</span> <span class="n">order_path</span><span class="p">(</span><span class="n">order</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">login_as</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span><span class='line'>    <span class="n">open_session</span> <span class="k">do</span> <span class="o">|</span><span class="n">sess</span><span class="o">|</span>
</span><span class='line'>      <span class="n">sess</span><span class="o">.</span><span class="n">post</span> <span class="n">login_path</span><span class="p">,</span> <span class="nb">name</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="ss">password</span><span class="p">:</span> <span class="s2">&quot;secret&quot;</span>
</span><span class='line'>      <span class="n">sess</span><span class="o">.</span><span class="n">follow_redirect!</span>
</span><span class='line'>      <span class="n">assert_equal</span> <span class="n">root_path</span><span class="p">,</span> <span class="n">sess</span><span class="o">.</span><span class="n">path</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The test above covers several of the features I just mentioned: multiple requests spread over different controllers, multiple sessions, and so on.  Also, since integration tests don&rsquo;t map directly to any specific source file but rather wander all around your application, they&rsquo;re named and organized according to functional scenarios rather than code.</p>

<p>Integration tests run a lot more code, both within your application and the Rails stack as well as in the tests themselves, and usually require a more involved setup.  You should therefore expect that they will run slower than more dense controller tests - anywhere from 5x to 10x slower in terms of assertions run per second is what I&rsquo;ve observed, depending on test complexity.</p>

<p>The syntax used by integration tests has a lot in common with the API used for controller tests with a few additions specific to their use case:</p>

<ul>
<li>Helpers for simulating different types of HTTP requests and managing sessions</li>
<li>Specialized assertions for verifying information specific to the HTTP response, rendered page</li>
<li>Access to routing helper methods, fixture data, and other Rails goodies</li>
</ul>


<p>The resulting tool set gives developers an API for making requests and verifying the results, albeit one that requires a lot of low-level knowledge of the application and its architecture.  Think of it as a not-terribly-bright client talking to the application.</p>

<h3>Acceptance Tests</h3>

<p>OK, so integration tests can push simulated requests through the complete Rails software stack - the router, controllers, models, and so on.  But is that really your whole application?  Ten years ago the answer would probably have been &ldquo;yes&rdquo;, but today you might want to think about what else your application has going on.  The typical Rails application has changed a lot since those days, and most modern web apps now include complex scripting and styling that also needs to be tested.  If your application only uses &ldquo;sprinkles&rdquo; of Javascript, then integration tests might be just what you need.  But now, when I find myself spending 50% or more of my development time working on front-end codefor some applications, I don&rsquo;t feel confident using only simulated HTTP requests.  I want something more like simulated interactions.</p>

<p>I use the term <em>acceptance test</em> to refer to a type of automated test that checks the <u>complete</u> application from the user&rsquo;s perspective and verifies that it meets certain requirements.  (The term has its origins in engineering, so there are many variations of this definition, but this is the one I use.)  As I see it, my acceptance testing stack needs two important features:</p>

<ol>
<li>Tests are defined with a <strong>user-oriented API</strong> that mirrors the actions a user would perform to navigate the application, trigger actions, fill in and select values in form fields, and so on.</li>
<li>The test harness has to exercise the <strong>whole application</strong> including script and stylesheet evaluation.  You need this in order to ensure that the test sees what a real user would see when viewing the application.  Otherwise, it might be possible, for example, to click a button that&rsquo;s not visible or not active.</li>
</ol>


<p>Rails integration tests won&rsquo;t do either of these things on their own, so they don&rsquo;t qualify as acceptance tests.  This is why I add <a href="https://github.com/jnicklas/capybara">Capybara</a> to my suite for these kinds of high level tests which gives me all of the following added features:</p>

<ul>
<li>Pluggable back-end drivers that give you several options ranging from simple (markup only) to the full-featured (full evaluation of Javascript and CSS styles)</li>
<li>A slick, natural API that allows tests to be defined in language that mimics user interaction with the browser</li>
<li>Management of multiple sessions</li>
<li>Automatic following of redirect responses</li>
<li>Ability to follow external URLs</li>
</ul>


<p>The acceptance test below is similar to the Rails integration test presented previously, and it showcases many of the Capybara features from the list above.  It&rsquo;s installed and integrated with Minitest and Rails using the <a href="https://github.com/blowmage/minitest-rails-capybara">minitest-rails-capybara</a> gem.</p>

<figure class='code'><figcaption><span>test/features/shopper_interactions_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="n">feature</span> <span class="s2">&quot;Shopper Interactions&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">scenario</span> <span class="s2">&quot;place order and check orders admin&quot;</span><span class="p">,</span> <span class="ss">js</span><span class="p">:</span> <span class="kp">true</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">shopper</span> <span class="o">=</span> <span class="n">login_as</span> <span class="n">users</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span>
</span><span class='line'>    <span class="n">admin</span> <span class="o">=</span> <span class="n">login_as</span> <span class="n">users</span><span class="p">(</span><span class="ss">:administrator</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">product</span> <span class="o">=</span> <span class="n">products</span><span class="p">(</span><span class="ss">:rails_book</span><span class="p">)</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">visit</span> <span class="n">root_path</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">within</span> <span class="s2">&quot;div#cart&quot;</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;Your cart is empty.&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">within</span> <span class="s2">&quot;#entry_</span><span class="si">#{</span> <span class="n">product</span><span class="o">.</span><span class="n">id</span> <span class="si">}</span><span class="s2">&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">shopper</span><span class="o">.</span><span class="n">click_button</span> <span class="s2">&quot;Add to Cart&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">within</span> <span class="s2">&quot;#cart&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">shopper</span><span class="o">.</span><span class="n">within</span> <span class="s2">&quot;.current_item&quot;</span> <span class="k">do</span>
</span><span class='line'>        <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_css</span> <span class="s2">&quot;.quantity&quot;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="s2">&quot;1×&quot;</span>
</span><span class='line'>        <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_css</span> <span class="s2">&quot;.title&quot;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="n">product</span><span class="o">.</span><span class="n">title</span>
</span><span class='line'>        <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_css</span> <span class="s2">&quot;.price&quot;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s2">&quot;$%.2f&quot;</span><span class="p">,</span> <span class="n">product</span><span class="o">.</span><span class="n">price</span><span class="p">)</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_css</span> <span class="s2">&quot;.total_line .total_cell&quot;</span><span class="p">,</span> <span class="ss">text</span><span class="p">:</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s2">&quot;$%.2f&quot;</span><span class="p">,</span> <span class="n">product</span><span class="o">.</span><span class="n">price</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">click_button</span> <span class="s2">&quot;Checkout&quot;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">fill_in</span> <span class="s2">&quot;Name&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s2">&quot;Chris Kottom&quot;</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">fill_in</span> <span class="s2">&quot;Address&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s2">&quot;My house&quot;</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">fill_in</span> <span class="s2">&quot;Email&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s2">&quot;chris@example.com&quot;</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">select</span> <span class="s2">&quot;Credit Card&quot;</span><span class="p">,</span> <span class="ss">from</span><span class="p">:</span> <span class="s2">&quot;Pay type&quot;</span>
</span><span class='line'>    <span class="o">-&gt;</span> <span class="p">{</span> <span class="n">shopper</span><span class="o">.</span><span class="n">click_button</span> <span class="s2">&quot;Create Order&quot;</span> <span class="p">}</span><span class="o">.</span><span class="n">must_change</span> <span class="s2">&quot;Order.count&quot;</span><span class="p">,</span> <span class="mi">1</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;Thank you for your order.&quot;</span>
</span><span class='line'>    <span class="n">shopper</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;Your cart is empty.&quot;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">order</span> <span class="o">=</span> <span class="no">Order</span><span class="o">.</span><span class="n">last</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">visit</span> <span class="n">orders_path</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">within</span> <span class="s2">&quot;#orders #order_</span><span class="si">#{</span> <span class="n">order</span><span class="o">.</span><span class="n">id</span> <span class="si">}</span><span class="s2">&quot;</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">admin</span><span class="o">.</span><span class="n">must_have_css</span> <span class="s2">&quot;a[href=&#39;</span><span class="si">#{</span> <span class="n">order_path</span><span class="p">(</span><span class="n">order</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="si">}</span><span class="s2">&#39;]&quot;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">login_as</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span><span class='line'>    <span class="n">session</span> <span class="o">=</span> <span class="ss">Capybara</span><span class="p">:</span><span class="ss">:Session</span><span class="o">.</span><span class="n">new</span> <span class="ss">:poltergeist</span><span class="p">,</span> <span class="no">Rails</span><span class="o">.</span><span class="n">application</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">visit</span> <span class="n">root_path</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">click_link</span> <span class="s2">&quot;Login&quot;</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">fill_in</span> <span class="s2">&quot;Name&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">name</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">fill_in</span> <span class="s2">&quot;Password&quot;</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="s2">&quot;secret&quot;</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">click_button</span> <span class="s2">&quot;Save changes&quot;</span>
</span><span class='line'>    <span class="n">session</span><span class="o">.</span><span class="n">must_have_content</span> <span class="s2">&quot;Signed in as </span><span class="si">#{</span> <span class="n">user</span><span class="o">.</span><span class="n">name</span> <span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>    <span class="n">session</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The test uses the standard Capybara DSL which includes methods like <code>visit</code> and <code>click_button</code> combined with specialized Minitest-based assertions for verifying the presence of content and DOM elements that should be presented to the user.  The test is simple and direct enough to follow for both developers and business users alike.</p>

<p>Here, I&rsquo;m using the <a href="https://github.com/teampoltergeist/poltergeist">Poltergeist</a> driver for Capybara which piggybacks on the <a href="http://phantomjs.org/">PhantomJS</a> headless testing tool (separate install).  In this example, I&rsquo;m enabling Javascript evaluation by defining the test scenario with the <code>:js</code> option set to true, but in cases where I don&rsquo;t need that feature, Capybara will default to the <a href="https://github.com/brynary/rack-test">rack-test</a> back end for faster test execution.</p>

<p>You&rsquo;ll notice that the acceptance test above is longer LOC-wise than the equivalent integration test.  In part, that&rsquo;s because Capybara lets you fill in a virtual HTML form rather than just slinging requests and parameters at the router.  Also, given the added overhead of JS and CSS evaluaation and the fact that Capybara spins up a complete server for your application in a separate thread, the acceptance test is also substantially slower than the integration test - perhaps 2-4x slower for this example depending on the driver in use.</p>

<p>Some of you might be asking: why not use <a href="https://cucumber.io/">Cucumber</a> to define your acceptance tests?  Like a lot of hotnesses that have shown up on my radar over the years, I gave Cucumber a try, and I found it to be a poor fit for the way I work.  The additional layer of abstraction made it hard to keep sight of what my tests were supposed to be doing and, frankly, I&rsquo;ve never once been able to sell a customer on the benefits of transparency and shared test ownership of Cucumber-based suites that&rsquo;s the main selling point of a tool like Cucumber.  I can imagine that method of operation working in a larger organization that has dedicated test developers and business analysts working together on projects over a longer period of time, but for a freelancer, it&rsquo;s too much overhead.</p>

<h3>Conclusions?</h3>

<p>Each of these types of tests has its own strengths and weaknesses and is used for a different purpose in your Rails test suite.</p>

<ul>
<li>Controller tests are the fastest of the three and are great at isolating and fully exercising controller classes.  Use them to exhaustively test your controller classes in isolation from the view.</li>
<li>Integration tests strike a balance between faster, leaner controller tests and slower but more feature-rich acceptance tests.  I could see them being particularly effective at testing an API with a stateful component.</li>
<li>Acceptance testing as I describe here provides a framework for automated end-to-end testing of all layers of the modern web application with a super-friendly API.  If you&rsquo;re writing a standard server-rendered Rails application, especially with a substantial amount of client-side scripting, this would be part of my suite.</li>
</ul>


<p>So how do I use these different types of tests, you might be asking?  (If you&rsquo;ve gotten this far into the article, I&rsquo;m going to assume you&rsquo;re interested.)</p>

<ul>
<li>I write extensive controller tests in parallel with my controller code as I&rsquo;m filling in the logic.  The final test cases usually include success and (sometimes multiple) failure scenarios for each controller action which ensures that I finish with good coverage.  The individual tests are usually relatively short and sweet - control the preconditions and inputs, make assertions about the response and side effects as outlined above.</li>
<li>As my apps have come to include more Javascript in the past year or two, I&rsquo;ve gotten into the very good and responsible habit of writing more acceptance tests.  During that time, I&rsquo;ve grown more comfortable with the Capybara API and have standardized on the <a href="https://github.com/teampoltergeist/poltergeist">Poltergeist</a> driver when I need Javascript eval.  In the future, I&rsquo;m thinking about experimenting with writing some basic acceptance tests first before coding features where I have well-established requirements in advance, but right now at least, most of my acceptance tests are used for regression.</li>
<li>I don&rsquo;t use Rails integration tests at all.  For me, these provide less functionality and comfort than the equivalent acceptance tests based on Capybara, even if they do run somewhat slower.  As I mentioned above though, I could see myself using these for certain API-based applications in the future.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby and Rails Testing Changes Roundup]]></title>
    <link href="http://chriskottom.com/blog/2015/07/ruby-and-rails-testing-changes-roundup/"/>
    <updated>2015-07-04T21:18:48+02:00</updated>
    <id>http://chriskottom.com/blog/2015/07/ruby-and-rails-testing-changes-roundup</id>
    <content type="html"><![CDATA[<p><img class="no-border right" src="http://chriskottom.com/images/change_we_need.jpg" title="Change We Need" ></p>

<p>Ruby and Rails provide developers with an awesome set of tools for testing your code and applications. If you&rsquo;ve followed this blog at all, you&rsquo;re probably already aware that it&rsquo;s kind of a thing with me. :)</p>

<p>But both the language and the framework have active ecosystems, so if you want to survive and thrive as a developer, you need to be ready to commit a certain portion of your time and mental energy toward maintaining your skills and keeping up with the latest changes.  A number of these have come along since I shipped <a href="http://chriskottom.com/minitestcookbook/">The Minitest Cookbook</a>, and this is the summary of the most important and interesting that I&rsquo;ve been meaning to post for some time.<!--more--></p>

<h2>Minitest Expectation Syntax</h2>

<p><a href="http://chriskottom.com/blog/2015/04/unexpected-the-new-minitest-spec-syntax/">I&rsquo;ve written about the change to Minitest::Spec expectations before</a>, but as this is an essential change that will almost certainly require you to migrate some old code bases in the future, a quick review is warranted.</p>

<p>Minitest::Spec has historically worked by monkeypatching its expectation methods (<code>must_equal</code>, <code>must_include</code>, &hellip;) directly into every class which allowed developers to make assertions by calling methods directly on the object under test.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">User</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:admin</span><span class="p">)</span>  <span class="p">{</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">username</span><span class="p">:</span> <span class="s2">&quot;admin&quot;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;must have a username to be valid&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">must_be</span> <span class="ss">:valid?</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">username</span> <span class="o">=</span> <span class="kp">nil</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">wont_be</span> <span class="ss">:valid?</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This nice, human-readable syntax earned Minitest a lot of devotees over the years, many of whom were converting after years of using RSpec and liked the combination of familiarity and greater simplicity.</p>

<p>Since the release of Minitest 5.6 though, the preferred method of creating assertions requires that you wrap the object under test in a <strong>Minitest::Expectation</strong> object before calling the expectation methods on them.  That changes the test above to the following:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">User</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:admin</span><span class="p">)</span>  <span class="p">{</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">username</span><span class="p">:</span> <span class="s2">&quot;admin&quot;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;must have a username to be valid&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">admin</span><span class="p">)</span><span class="o">.</span><span class="n">must_be</span> <span class="ss">:valid?</span>
</span><span class='line'>    <span class="n">admin</span><span class="o">.</span><span class="n">username</span> <span class="o">=</span> <span class="kp">nil</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">admin</span><span class="p">)</span><span class="o">.</span><span class="n">wont_be</span> <span class="ss">:valid?</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>For the time being, both of these are supported, but the legacy syntax will be deprecated and later removed sometime in the not too distant future, so it&rsquo;s best to start writing future proofed code now rather than later.</p>

<h3>Related Links</h3>

<ul>
<li><a href="https://github.com/seattlerb/minitest/commit/9e78cc974f3ef0d9716f1cca2675753cf5f648d0">Added Minitest::Expectation value monad.</a> - the GitHub commit reference introducing the new syntax</li>
<li><a href="http://blog.zenspider.com/blog/2015/04/great-expectations.html">Great Expectations</a> - Ryan Davis’ blog post about the new syntax</li>
<li><a href="http://chriskottom.com/blog/2015/04/unexpected-the-new-minitest-spec-syntax/">Unexpected: The New Minitest::Spec Syntax</a> - my earlier post on the new syntax and the reasons for it</li>
</ul>


<h2>Rails Deprecations</h2>

<p>Rails 5 will deprecate two methods that have been commonly used in controller tests since the beginning: <code>assigns</code> and <code>assert_template</code>.  The rationale here is that testing with these kinds of methods is too invasive and too closely tied to the implementation of a feature instead of the observable effects produced by the system - e.g. the HTTP response code sent, redirects sent, session variables and cookies set, markup and data rendered, etc.  DHH has come right out in favor of writing more integration and acceptance tests, and this change signals a step toward establishing that style as a Rails best practice.</p>

<p>It took me some time to learn to love this change when I first heard about it.  Since the beginning, Rails has (rightly or wrongly) used instance variables as a way of passing state from controllers to templates, and the idea that we&rsquo;d suddenly stop testing that interface seemed wrong to me.  But most of us have generally negative feelings about controller tests anyway.  They often feel like busy work because they can be repetitive to write and feel unimportant to our test suite.  So I&rsquo;m personally really ready to start moving my <a href="http://martinfowler.com/bliki/TestPyramid.html">test pyramid</a> to more of a <a href="http://www.getautoma.com/blog/the-test-hourglass">test hourglass</a> (and hoping like crazy that it doesn&rsquo;t completely slow down my test runs).</p>

<h3>Related Links</h3>

<ul>
<li><a href="https://github.com/rails/rails/issues/18950">Deprecate assigns() and assert_template in controller testing</a> - the PR and subsequent discussion</li>
</ul>


<h2>Keyword Arguments for Rails Controller Request Helpers</h2>

<p>Rails 5 will also introduce a change to the controller and integration test helpers used to simulate all the various request types - <code>#get</code>, <code>#post</code>, and so on.  These methods have always taken in a number of optional Hashes for passing in request parameters, session variables, and flash parameters, respectively, so to send a request with only some of these defined, you might need to pass placeholder arguments:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">CommentController</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;posts a comment&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">post</span> <span class="ss">:create</span><span class="p">,</span>
</span><span class='line'>    <span class="p">{</span> <span class="n">user_id</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">comment</span><span class="p">:</span> <span class="s2">&quot;Awesome!&quot;</span> <span class="p">},</span>
</span><span class='line'>    <span class="kp">nil</span><span class="p">,</span>
</span><span class='line'>    <span class="p">{</span> <span class="ss">notice</span><span class="p">:</span> <span class="s2">&quot;Your comment has been posted.&quot;</span> <span class="p">}</span>
</span><span class='line'>    <span class="c1"># ...      </span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The <code>nil</code> here is complete noise, though, and it&rsquo;s not at all clear what any of these method arguments is supposed to represent.  Rails 5 fixes this by implementing the argument list using Ruby 2 keyword arguments which will allow the same test to be rewritten as:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">CommentController</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;posts a comment&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">post</span> <span class="ss">:create</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">params</span><span class="p">:</span> <span class="p">{</span> <span class="n">user_id</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">comment</span><span class="p">:</span> <span class="s2">&quot;Awesome!&quot;</span> <span class="p">},</span>
</span><span class='line'>    <span class="ss">flash</span><span class="p">:</span> <span class="p">{</span> <span class="ss">notice</span><span class="p">:</span> <span class="s2">&quot;Your comment has been posted.&quot;</span> <span class="p">}</span>
</span><span class='line'>    <span class="c1"># ...      </span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The three original arguments (<code>params</code>, <code>session</code>, and <code>flash</code>) will get the most use, but additional arguments for <code>body</code> and <code>xhr</code> are also supported where they&rsquo;re needed.</p>

<p>The non-keyword argument list will eventually be phased out completely, so you&rsquo;ll want to start getting used to the new syntax and using it as you start new projects based on Rails 5.</p>

<h3>Related Links</h3>

<ul>
<li><a href="https://github.com/rails/rails/pull/18323">Use kwargs in ActionController::TestCase and ActionDispatch::Integration HTTP methods</a> - the PR</li>
</ul>


<h2>A New Rails Test Runner</h2>

<p><a href="http://tenderlovemaking.com/2015/01/23/my-experience-with-minitest-and-rspec.html">Tenderlove&rsquo;s comparison of Minitest and RSpec</a> pointed out some of the pros and cons of both frameworks, and while he prefers Minitest for his own projects, one place where RSpec shines is in its failure and error output.  That&rsquo;s because it lets the developer simply copy and paste one line from the report to re-run a single failing test.  Minitest certainly supports <a href="http://chriskottom.com/blog/2014/12/command-line-flags-for-minitest-in-the-raw/">various options for running individual and selected tests</a>, but they&rsquo;re not as simple or as intuitive as RSpec&rsquo;s interface.</p>

<p>The post was widely shared and gained a lot of traction within the community.  The discussions that followed led to the development of <a href="https://github.com/seattlerb/minitest-sprint">minitest-sprint</a> and added momentum to projects already underway like the new Rails-bundled test runner. (<a href="https://twitter.com/kaspth">@kaspth</a> points out that the first PR for what eventually became the Rails runner predates Tenderlove&rsquo;s post by a bit.) It replaces the Rake tasks that had previously been the preferred method of running tests for Rails applications in order to avoid the use of environment variables on the command line.  As of Rails 5, you&rsquo;ll be able to run your tests using the <code>rails</code> executable like so:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>rails <span class="nb">test</span>                              <span class="c"># run all tests in your test directory</span>
</span><span class='line'><span class="nv">$ </span>rails <span class="nb">test test</span>/models                  <span class="c"># run all tests from the specified directory</span>
</span><span class='line'><span class="nv">$ </span>rails <span class="nb">test test</span>/models/user_test.rb     <span class="c"># run the specified test case</span>
</span><span class='line'><span class="nv">$ </span>rails <span class="nb">test test</span>/models/user_test.rb:26  <span class="c"># run the test found at the specified file and line</span>
</span></code></pre></td></tr></table></div></figure>


<p>Failures and errors will be displayed by filename and line number to allow for easy re-running just by copying and pasting - same as with RSpec - and the the PR that introduces this change also updates the Rake task, so you&rsquo;ll still get the benefit of these new features even if your hands insist on typing <code>rake test</code>.</p>

<h3>Related Links</h3>

<ul>
<li><a href="https://github.com/rails/rails/pull/19216"><code>bin/rails test</code> runner (rerun snippets, run tests by line, option documentation)</a> - initial PR introducing the new runner</li>
<li><a href="https://github.com/rails/rails/pull/19571">Improve Test Runner&rsquo;s Minitest integration.</a> - subsequent PR to improve the implementation</li>
</ul>


<p>I&rsquo;ll be looking to ship a big update to <a href="http://chriskottom.com/minitestcookbook/">The Minitest Cookbook</a> sometime before the end of the year (which will be freely available to those of you who&rsquo;ve already purchased the book), and all of these changes will figure prominently in the new version.  In the meantime though, I&rsquo;ll be trying to work them into my coding to see which ones produce changes in how I work and which ones are less important.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Minitest::Benchmark: A Practical Example]]></title>
    <link href="http://chriskottom.com/blog/2015/05/minitest-benchmark-a-practical-example/"/>
    <updated>2015-05-07T11:36:30+02:00</updated>
    <id>http://chriskottom.com/blog/2015/05/minitest-benchmark-a-practical-example</id>
    <content type="html"><![CDATA[<p>In the <a href="http://chriskottom.com/blog/2015/04/minitest-benchmark-an-introduction/">last post</a>, we looked at Minitest::Benchmark as a high-level concept and sketched out a basic structure for how we might test with them.  I don&rsquo;t know about anyone else, but I&rsquo;ve gotta say: the process of researching and writing that post gave me a lot of perspective on what Benchmarks do and where my own tests could benefit from their use.  There&rsquo;s a limit, though, to what you can learn from looking at technology from 10,000 feet.  What usually delivers the most bang for my buck is seeing how a thing is used in practice, trying it out myself, and seeing where I&rsquo;m getting value from it.</p>

<p>In this post, we&rsquo;re going to take a first crack at a practical benchmarking example to get started down that path.  When we&rsquo;re finished, we&rsquo;ll reflect on what we&rsquo;ve observed and what, if anything, we&rsquo;ve learned from it.<!--more--></p>

<h2>The code under test</h2>

<p><img class="right no-border" src="http://chriskottom.com/images/get_sorted.png" width="250" title="Keep Calm and Get Sorted" ></p>

<p>Recall from the <a href="http://chriskottom.com/blog/2015/04/minitest-benchmark-an-introduction/">previous post</a> that Benchmarks run the code in a given block against progressively larger workloads.  So as much as I didn&rsquo;t want it to come to this, the example that I chose for this post is <strong>sort algorithms</strong>.  Why?</p>

<ul>
<li>They&rsquo;re familiar to a lot of programmers from CS courses they took years ago.  (Or in some cases, even decades&hellip;)</li>
<li>Their performance characteristics are comprehensible and predictable.</li>
<li>The workload is easily quantifiable as the size of the list of items to be sorted.</li>
</ul>


<p>For demonstration purposes, it&rsquo;s enough to implement just one or two sorting algorithms, preferably with differing performance characteristics, and to build out a practical example project.  In this case, I took <a href="https://en.wikipedia.org/wiki/Insertion_sort">insertion sort</a> and <a href="https://en.wikipedia.org/wiki/Merge_sort">merge sort</a> as examples.</p>

<figure class='code'><figcaption><span>lib/sorters.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Sorters</span>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Base</span>
</span><span class='line'>    <span class="kp">attr_reader</span> <span class="ss">:values</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
</span><span class='line'>      <span class="vi">@values</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">dup</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Insertion Sort</span>
</span><span class='line'>  <span class="c1"># Move elements one by one into their proper position</span>
</span><span class='line'>  <span class="c1"># within the sorted portion of the collection.</span>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Insertion</span> <span class="o">&lt;</span> <span class="no">Base</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">sort</span>
</span><span class='line'>      <span class="c1"># insertion sort implementation...</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># Merge Sort</span>
</span><span class='line'>  <span class="c1"># Divide the collection into two halves, and sort each half.</span>
</span><span class='line'>  <span class="c1"># Then combine the sorted halves and sort the result.</span>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Merge</span> <span class="o">&lt;</span> <span class="no">Base</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">sort</span>
</span><span class='line'>      <span class="c1"># merge sort implementation...</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>(For those who are interested, all of the main source files for this post can be found in a <a href="https://gist.github.com/chriskottom/22ed11c5b332cd98bfce">gist</a>.)</p>

<p>Getting set up to test this code is similar to other projects you may have seen.  First, we&rsquo;ll want to create a Rakefile with tasks for running our tests.  While it&rsquo;s possible to run all tests with a single task, it&rsquo;s not going to be very useful.  Why?  Because when you&rsquo;re using unit tests to guide your development, you want to keep the feedback loop between running tests and writing code as tight as possible.  Not unlike acceptance tests in your Rails applications, a properly conceived Benchmark will most likely take more time to execute than you&rsquo;ll want to spend during regular development, TDD or otherwise.  For this reason, I&rsquo;d recommend setting up a separate <code>:bench</code> task that you&rsquo;ll use to run your benchmarks as shown below.</p>

<figure class='code'><figcaption><span>Rakefile </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;rake/testtask&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="ss">Rake</span><span class="p">:</span><span class="ss">:TestTask</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:test</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
</span><span class='line'>  <span class="n">t</span><span class="o">.</span><span class="n">libs</span> <span class="o">=</span> <span class="sx">%w(lib test)</span>
</span><span class='line'>  <span class="n">t</span><span class="o">.</span><span class="n">pattern</span> <span class="o">=</span> <span class="s1">&#39;test/**/*_test.rb&#39;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="ss">Rake</span><span class="p">:</span><span class="ss">:TestTask</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:bench</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
</span><span class='line'>  <span class="n">t</span><span class="o">.</span><span class="n">libs</span> <span class="o">=</span> <span class="sx">%w(lib test)</span>
</span><span class='line'>  <span class="n">t</span><span class="o">.</span><span class="n">pattern</span> <span class="o">=</span> <span class="s1">&#39;test/**/*_benchmark.rb&#39;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">task</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="ss">:test</span>
</span></code></pre></td></tr></table></div></figure>


<p>Next, you&rsquo;ll want to set up the test helper file that will be required at the top of each of your tests.  This will be used both for regular unit tests and performance benchmarks, so you&rsquo;ll want to make sure that you explicitly require <code>minitest/benchmark</code> which is not otherwise required by <code>minitest/autorun</code>.</p>

<p>For the purposes of this example, I&rsquo;ve also added a RandomArrayGenerator helper module with that I can use to generate lists of randomized numbers and Strings which my tests will use as targets for sorting.</p>

<figure class='code'><figcaption><span>test/test_helper.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;minitest/autorun&quot;</span>
</span><span class='line'><span class="nb">require</span> <span class="s2">&quot;minitest/benchmark&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="nb">require</span> <span class="s2">&quot;sorters&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">module</span> <span class="nn">RandomArrayGenerator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">random_numbers</span><span class="p">(</span><span class="n">size</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
</span><span class='line'>    <span class="n">result</span> <span class="o">=</span> <span class="o">[]</span>
</span><span class='line'>    <span class="n">size</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="nb">rand</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>    <span class="n">result</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">random_strings</span><span class="p">(</span><span class="n">size</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">length</span> <span class="o">=</span> <span class="mi">8</span><span class="p">)</span>
</span><span class='line'>    <span class="n">result</span> <span class="o">=</span> <span class="o">[]</span>
</span><span class='line'>    <span class="n">size</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="n">random_string</span><span class="p">(</span><span class="n">length</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>    <span class="n">result</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">random_string</span><span class="p">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">8</span><span class="p">)</span>
</span><span class='line'>    <span class="p">(</span><span class="mi">1</span><span class="o">.</span><span class="n">.length</span><span class="p">)</span><span class="o">.</span><span class="n">inject</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">memo</span><span class="p">,</span> <span class="n">n</span><span class="o">|</span> <span class="n">memo</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="nb">rand</span><span class="p">(</span><span class="mi">93</span><span class="p">)</span> <span class="o">+</span> <span class="mi">33</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>At this point, I realized that the Benchmarks I&rsquo;m about to write don&rsquo;t mean much if the algorithms I&rsquo;ve implemented don&rsquo;t work as expected, so I threw together a simple unit test that checks the results of my Sorter classes against the results of Ruby&rsquo;s <code>Array#sort</code> method.</p>

<figure class='code'><figcaption><span>test/sort_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">SortTest</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Test</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">RandomArrayGenerator</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">setup</span>
</span><span class='line'>    <span class="vi">@numbers</span> <span class="o">=</span> <span class="n">random_numbers</span><span class="p">(</span><span class="mi">25</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@strings</span> <span class="o">=</span> <span class="n">random_strings</span><span class="p">(</span><span class="mi">25</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_insertion_sort_numbers</span>
</span><span class='line'>    <span class="n">sorted</span> <span class="o">=</span> <span class="vi">@numbers</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="n">sorter</span> <span class="o">=</span> <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Insertion</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@numbers</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">sorted</span><span class="p">,</span> <span class="n">sorter</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_insertion_sort_strings</span>
</span><span class='line'>    <span class="n">sorted</span> <span class="o">=</span> <span class="vi">@strings</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="n">sorter</span> <span class="o">=</span> <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Insertion</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@strings</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">sorted</span><span class="p">,</span> <span class="n">sorter</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_merge_sort_numbers</span>
</span><span class='line'>    <span class="n">sorted</span> <span class="o">=</span> <span class="vi">@numbers</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="n">sorter</span> <span class="o">=</span> <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Merge</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@numbers</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">sorted</span><span class="p">,</span> <span class="n">sorter</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_merge_sort_strings</span>
</span><span class='line'>    <span class="n">sorted</span> <span class="o">=</span> <span class="vi">@strings</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="n">sorter</span> <span class="o">=</span> <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Merge</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@strings</span><span class="p">)</span>
</span><span class='line'>    <span class="n">assert_equal</span> <span class="n">sorted</span><span class="p">,</span> <span class="n">sorter</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Once we&rsquo;ve seen that this test passes, we&rsquo;re ready to implement our Benchmark.  As a first step, we need to define the range of values and test data that can be used across the various runs.  As mentioned in the <a href="http://chriskottom.com/blog/2015/04/minitest-benchmark-an-introduction/">previous post</a>, you define the range by overriding the <code>bench_range</code> class method as we&rsquo;ve done below.  The resulting values will be: <code>[10, 100, 1_000, 10_000, 25_000]</code>.</p>

<figure class='code'><figcaption><span>test/sort_benchmark.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">SortBenchmark</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Benchmark</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">bench_range</span>
</span><span class='line'>    <span class="n">bench_exp</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10_000</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">25_000</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Practically speaking, it takes a little trial and error to find the right range for each Benchmark.  In some cases the default range (powers of 10 up to 10,000) might be just what you need, but my experiments so far have shown that while larger values may produce better regression function fit, they can also be prohibitively slow to run.  For example, an attempt at running bubble sort for arrays of 100,000 elements took several minutes to execute.  Ain&rsquo;t nobody got time fo dat.</p>

<p>Next, we&rsquo;ll initialize collections of test data with the number of elements required for each value from our <code>bench_range</code>.  To do that, we want to use a normal Minitest <code>setup</code> method implementation and the helper mixin that we wrote into the test helper.</p>

<figure class='code'><figcaption><span>test/sort_benchmark.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">SortBenchmark</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Benchmark</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">RandomArrayGenerator</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">bench_range</span>
</span><span class='line'>    <span class="n">bench_exp</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10_000</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">25_000</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">setup</span>
</span><span class='line'>    <span class="vi">@sort_targets</span> <span class="o">=</span> <span class="p">{}</span>
</span><span class='line'>    <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">bench_range</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span>
</span><span class='line'>      <span class="vi">@sort_targets</span><span class="o">[</span><span class="n">n</span><span class="o">]</span> <span class="o">=</span> <span class="n">random_numbers</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>We&rsquo;re finally ready to specify our benchmark tests, but first we need to have a hypothesis about the performance characteristics for each algorithm.  Fortunately for us, both of these have been studied by generations of CS students, so we already have some expectations:</p>

<ul>
<li>Insertion Sort - varies as the square of the number of elements (O(n&sup2;)) &rarr; <code>assert_performance_power</code></li>
<li>Merge Sort - varies as the logarithm of the number of elements (O(n log n)) &rarr; <code>assert_performance_power</code></li>
</ul>


<p>So our tests end up looking like this:</p>

<figure class='code'><figcaption><span>test/sort_benchmark.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">&quot;test_helper&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">SortBenchmark</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Benchmark</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">bench_insertion_sort</span>
</span><span class='line'>    <span class="n">assert_performance_power</span> <span class="k">do</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span>
</span><span class='line'>      <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Insertion</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@sort_targets</span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">bench_merge_sort</span>
</span><span class='line'>    <span class="n">assert_performance_power</span> <span class="k">do</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span>
</span><span class='line'>      <span class="ss">Sorters</span><span class="p">:</span><span class="ss">:Merge</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@sort_targets</span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Let&rsquo;s see how our assumptions measure up to reality:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>rake bench
</span><span class='line'>Run options: --seed 24581
</span><span class='line'>
</span><span class='line'><span class="c"># Running:</span>
</span><span class='line'>
</span><span class='line'>bench_insertion_sort     0.000038        0.000566        0.016178        1.567154        9.789949
</span><span class='line'>Fbench_merge_sort        0.000055        0.000392        0.004488        0.050258        0.134776
</span><span class='line'>.
</span><span class='line'>
</span><span class='line'>Finished in 11.627200s, 0.1720 runs/s, 0.1720 assertions/s.
</span><span class='line'>
</span><span class='line'>  1<span class="o">)</span> Failure:
</span><span class='line'>  SortBenchmark#bench_insertion_sort <span class="o">[</span>/home/ck1/Projects/tiny_projects/sorting_algorithms/test/sort_benchmark.rb:18<span class="o">]</span>:
</span><span class='line'>  Expected 0.8140132616129555 to be &gt;<span class="o">=</span> 0.99.
</span><span class='line'>
</span><span class='line'>  2 runs, 2 assertions, 1 failures, 0 errors, 0 skips
</span></code></pre></td></tr></table></div></figure>


<p>It looks like our merge sort implementation has matched expectations, but insertion sort is off.  There are plenty of possible reasons for the results we&rsquo;re getting here:</p>

<ul>
<li>The algorithm isn&rsquo;t optimal.  In order to know that though, we&rsquo;d need to better understand whether we&rsquo;re overperforming or underperforming with respect to the regression function.</li>
<li>The test data isn&rsquo;t as random as expected.  Insertion sort performs better (closer to <em>linear</em>) with data sets that are better sorted.  (And in fact, further testing showed a better correlation with linear functions than power funtions for the values tested, though still not with an R-squared of 0.99 or more.)</li>
<li>Natural variability in randomized data and different runs will produce different results.  That&rsquo;s unlikely to overcome the kind of gap you see here with our insertion sort, but it could result in failures on certain test runs for merge sort.</li>
<li>External and interpreter-specific factors (e.g. garbage collection) could affect results.</li>
</ul>


<p>And even though I&rsquo;ve got a failing test here, I&rsquo;m still getting some valuable feedback from it.  I can see how closely my results map to a specific fit type which gives me some insight into how well the code is likely to perform with larger and larger inputs.  Like any failing test, it could be telling me that my code needs to improve or it could be telling me that my <em>tests</em> need to improve.</p>

<p>I&rsquo;ll be honest with you: I&rsquo;m just getting my feet wet with Minitest::Benchmark.  I still have plenty to learn, but I can see opportunities to include it in my suites in the future as:</p>

<ul>
<li>An initial target for defining code performance characteristics</li>
<li>A defensive measure to catch potential future regressions</li>
</ul>


<p>In the next installment of this series, I&rsquo;m going to take a look at how we might use this kind of testing to run benchmarks against a typical Rails application.</p>

<h3>Additional Resources:</h3>

<ul>
<li><a href="https://gist.github.com/chriskottom/22ed11c5b332cd98bfce">Minitest::Benchmark example</a> - gist containing sample source for this post</li>
<li><a href="http://www.sorting-algorithms.com/">Sorting Algorithms Animations</a> - a great site for visualizing different algorithms</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Minitest::Benchmark: An Introduction]]></title>
    <link href="http://chriskottom.com/blog/2015/04/minitest-benchmark-an-introduction/"/>
    <updated>2015-04-28T11:50:30+02:00</updated>
    <id>http://chriskottom.com/blog/2015/04/minitest-benchmark-an-introduction</id>
    <content type="html"><![CDATA[<p>As more developers have started to use Minitest, the number of resources available for learning about the framework has gradually been growing.  We&rsquo;ve never been short on cheat sheets or references, but as the community has grown, we&rsquo;ve seen more and more articles focused on specific aspects of the framework being published.  That&rsquo;s good for everyone involved.</p>

<p>One area where there&rsquo;s still very little information available, though, is Minitest benchmarks.  If you&rsquo;ve looked into the framework at all, you&rsquo;re probably aware that it allows developers to make assertions about the performance of the code they write.  Still, most developers never or rarely use this feature or understand what it does or how to get started.  In this first post of a three-part series, I want to explain what Minitest::Benchmark is and how it works in a clear, easy to understand way.<!--more--></p>

<h2>What&rsquo;s a benchmark good for?</h2>

<p>The word <em>benchmark</em> is seriously overloaded within the IT domain, so developers make all kinds of assumptions about what Minitest::Benchmark is and does.  Well, at least I did.  Before I started digging into it, I&rsquo;d always assumed that benchmarks were a tool for demonstrating that a given piece of code could be executed within a certain time limit.  But think about that for a moment.  Pass or fail, what would the <strong>absolute performance</strong> of a given amount of work within a testing environment tell me about the performance of my application in production?  Practically nothing of value.  While my definition wasn&rsquo;t exactly wrong, it wasn&rsquo;t complete either.</p>

<p>Here&rsquo;s what I found: a Benchmark in Minitest is a specialized test (actually a subclass of Minitest::Test) that executes the same block of code repeatedly with varied inputs to show the <strong>relative performance of the algorithm against increasing demands</strong>.  It does not assert, for example, that a method or chunk of code will execute within a given duration; rather, it makes predictions about how execution time will change with different inputs and workloads.</p>

<p>In order to clarify what a Benchmark does, we&rsquo;ll want to understand it as a process with four steps:</p>

<ol>
<li>Define a range of inputs.</li>
<li>Assert the performance of your algorithm.</li>
<li>Execute the benchmark.</li>
<li>Check the validity of your assertion.</li>
</ol>


<p>Let&rsquo;s break this down further so that we can understand each of these individually.</p>

<h2>Step 1: Define a range of inputs.</h2>

<p>Each Benchmark needs a range of values that will be fed to the code under test during execution, and this is defined by the <code>bench_range</code> class method.  Because it&rsquo;s the result of a class method, the same range is use for all benchmark tests within the same class.  The values in the returned Array must be numeric and should, in most cases, translate into an increasing workload.</p>

<p>The Minitest::Benchmark base class has a default implementation of <code>bench_range</code> that returns an exponential progression of powers of 10 from 1 through 10,000 as shown here:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>irb<span class="o">(</span>main<span class="o">)</span>:001:0&gt; Minitest::Benchmark.bench_range
</span><span class='line'><span class="o">=</span>&gt; <span class="o">[</span>1, 10, 100, 1000, 10000<span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can also override this implementation for each Benchmark subclass, and Minitest provides helper functions for defining both linear and exponential numeric progressions.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>irb<span class="o">(</span>main<span class="o">)</span>:002:0&gt; Minitest::Benchmark.bench_linear<span class="o">(</span>0, 50<span class="o">)</span>
</span><span class='line'><span class="o">=</span>&gt; <span class="o">[</span>0, 10, 20, 30, 40, 50<span class="o">]</span>
</span><span class='line'>irb<span class="o">(</span>main<span class="o">)</span>:003:0&gt; Minitest::Benchmark.bench_linear<span class="o">(</span>0, 256, 64<span class="o">)</span>
</span><span class='line'><span class="o">=</span>&gt; <span class="o">[</span>0, 64, 128, 192, 256<span class="o">]</span>
</span><span class='line'>irb<span class="o">(</span>main<span class="o">)</span>:004:0&gt; Minitest::Benchmark.bench_exp<span class="o">(</span>1, 100_000<span class="o">)</span>
</span><span class='line'><span class="o">=</span>&gt; <span class="o">[</span>1, 10, 100, 1000, 10000, 100000<span class="o">]</span>
</span><span class='line'>irb<span class="o">(</span>main<span class="o">)</span>:005:0&gt; Minitest::Benchmark.bench_exp<span class="o">(</span>1, 256, 2<span class="o">)</span>
</span><span class='line'><span class="o">=</span>&gt; <span class="o">[</span>1, 2, 4, 8, 16, 32, 64, 128, 256<span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Step 2: Assert the performance of your algorithm.</h2>

<p>At the core of any Benchmark test is an assertion about the performance of your code given an arbitrary amount of work to do.  There are five different assertions supported out of the box:</p>

<ul>
<li><code>assert_performance_constant</code> - Execution time should remain constant regardless of inputs.</li>
<li><code>assert_performance_linear</code> - Execution time should increase in proportion to workload.</li>
<li><code>assert_performance_logarithmic</code> - Execution time approaches a maximum limit.</li>
<li><code>assert_performance_exponential</code> - Execution time increases exponentially with workload.</li>
<li><code>assert_performance_power</code> - Execution time increases with workload according to a power function relation.</li>
</ul>


<p>Like any other kind of test, the assertion is essentially a prediction about the way your code should behave (or in this case, perform) given certain inputs.  These predictions can be expressed as mathematical formulas which in turn be expressed graphically.</p>

<p><img class="center no-border" src="http://chriskottom.com/images/benchmark_fits.png" width="750" title="Minitest::Benchmark Fit Types" ></p>

<p>Don&rsquo;t be intimidated by the math here.  It&rsquo;s actually quite intuitive what each of these things mean:</p>

<ul>
<li><em>x</em> is the numeric input provided to the code under test which represents a certain amount of work to be performed by the code under test.</li>
<li><em>y</em> is the predicted execution time resulting from a given input.</li>
<li><em>a</em> and <em>b</em> are implementation-specific constants that affect the shape of the curve.</li>
</ul>


<p>In each case, the assertion method takes two arguments: a threshold value representing how closely the observed execution times match the predictions and a block representing the code under test.  We&rsquo;ll circle back to these shortly.</p>

<figure class='code'><figcaption><span>test/benchmarks/bench_foo.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">BenchFoo</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Benchmark</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">bench_foo</span>
</span><span class='line'>    <span class="n">assert_performance_linear</span> <span class="mi">0</span><span class="o">.</span><span class="mi">99</span> <span class="k">do</span> <span class="o">|</span><span class="n">input</span><span class="o">|</span>
</span><span class='line'>      <span class="c1"># the code to be benchmarked</span>
</span><span class='line'>      <span class="c1"># is passed as a block</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Step 3: Execute the benchmark.</h2>

<p>Minitest runs the benchmark by executing the block once for each input value returned by <code>bench_range</code>.  With each execution, it measures the running time and stores it for later comparison.</p>

<p>While your benchmark runs, Minitest will print out the times for each execution of the code under test.  The output below is an example from a sample benchmark.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>ruby <span class="nb">test</span>/benchmarks/bench_types.rb
</span><span class='line'>Run options: --seed 23432
</span><span class='line'>
</span><span class='line'><span class="c"># Running:</span>
</span><span class='line'>
</span><span class='line'>bench_fib        0.000020        0.000008        0.000027        0.000447
</span><span class='line'>.bench_snooze    0.463001        0.281439        0.067537        0.459881
</span><span class='line'>.
</span><span class='line'>
</span><span class='line'>Finished in 2.825755s, 0.7078 runs/s, 0.7078 assertions/s.
</span><span class='line'>
</span><span class='line'>2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
</span></code></pre></td></tr></table></div></figure>


<h2>Step 4: Check the validity of your assertion.</h2>

<p>Let&rsquo;s consider what we have by the time we reach the final step of the process:</p>

<ul>
<li>An assumption about the general pattern of performance for the algorithm (determined by the assertion type)</li>
<li>A threshold number describing how closely we expect observed values to match predictions</li>
<li>The range of inputs used to conduct the benchmark</li>
<li>Observed execution times for the code under test for each input value in the range</li>
</ul>


<p>Using all of this and the awesome power of <strong>MATH</strong>, Minitest can determine the optimal values for the coefficients (recall: <em>a</em> and <em>b</em> from the formulas mentioned above).  By &ldquo;optimal&rdquo; in this case, we mean the values of <em>a</em> and <em>b</em> such that an equation of the form indicated by the assertion type provides the best representation and prediction of the observed values.  That might sound complicated, but essentially, it&rsquo;s answering the question: what&rsquo;s the best formula for predicting execution time?</p>

<p>As soon as these values are known, Minitest is also able to quantify how closely our predictions match the real, observed values by computing the <em>coefficient of determination</em> - commonly known as the <em>R-squared</em> value.  Without going into the gory technical details, R-squared is just a number between 0.0 and 1.0 that measures how closely the computed function matches the real observed data with a larger value indicating a closer match.</p>

<p>And that brings us back to our test code.  Recall that we provided a numeric threshold value when we wrote the original assertion?  Well, if the R-squared value is greater than the threshold value we passed to the assertion, it means that the performance fits with the expected model, and our assertion succeeds; if R-squared is less than the threshold though, the assertion fails.  So in this way, we haven&rsquo;t demonstrated that our code is fast or slow, but rather that it performs according to one of these models.</p>

<p>Hopefully that explains a little better about Minitest::Benchmark and what it might be used for.  In the next installment, we&rsquo;ll take a look at how we might be able to apply this knowledge within a realistic use case, and try to understand the value it can provide us.</p>

<h3>Additional Resources:</h3>

<ul>
<li><a href="https://en.wikipedia.org/wiki/Regression_analysis">Regression analysis</a></li>
<li><a href="https://en.wikipedia.org/wiki/Coefficient_of_determination">Coefficient of determination</a></li>
<li><a href="http://www.revision-zero.org/benchmarking">Ruby Benchmarking &amp; Complexity</a> - one of the only detailed technical articles I found on Minitest::Benchmark</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unexpected: The New Minitest::Spec Syntax]]></title>
    <link href="http://chriskottom.com/blog/2015/04/unexpected-the-new-minitest-spec-syntax/"/>
    <updated>2015-04-14T07:27:59+02:00</updated>
    <id>http://chriskottom.com/blog/2015/04/unexpected-the-new-minitest-spec-syntax</id>
    <content type="html"><![CDATA[<p>A lot of of developers got started with Minitest during the past few years because of Minitest::Spec.  Particularly in the case of seasoned RSpec users, the API and syntax of spec-style testing have provided a smoother transition between the two tools and enabled them to leverage all the experience and habits they&rsquo;ve built up over the years.  Yesterday&rsquo;s release of Minitest 5.6.0 brought some important changes to the framework, and even though your existing tests will keep on working as they always have, you&rsquo;ll want to pay attention to avoid unpleasant surprises in the future.  This post explains what you should expect and why it&rsquo;s happening.<!--more--></p>

<p>(Wordplay aside, <a href="https://github.com/seattlerb/minitest/commit/9e78cc974f3ef0d9716f1cca2675753cf5f648d0">this change</a> has been in the works for several weeks already and available for review on GitHub.)</p>

<h2>A Little Background</h2>

<p>If you&rsquo;re already a Minitest::Spec user, you know how the syntax works.  Instead of calling assertion methods within your test, the framework monkeypatches expectation methods directly into Module, and you define expectations directly on the object under test as shown here.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Lebowski</span>
</span><span class='line'>  <span class="kp">attr_accessor</span>  <span class="ss">:name</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">name</span> <span class="o">=</span> <span class="s2">&quot;Jeffrey&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="nb">name</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">abide?</span>
</span><span class='line'>    <span class="kp">true</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">module</span> <span class="nn">Minitest::Expectations</span>
</span><span class='line'>  <span class="n">alias_method</span> <span class="ss">:must</span><span class="p">,</span> <span class="ss">:must_be</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">describe</span> <span class="s2">&quot;Lebowski&quot;</span><span class="p">,</span> <span class="s2">&quot;old syntax&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:the_dude</span><span class="p">)</span>  <span class="p">{</span> <span class="no">Lebowski</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s2">&quot;Jeff&quot;</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should abide&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">the_dude</span><span class="o">.</span><span class="n">must</span> <span class="ss">:abide?</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The latest version introduces a new <strong>Minitest::Expectation</strong> class that exposes all the familiar expectation methods and wraps the object under test.  You&rsquo;ll be able to create a new instance of the class using the <code>_</code> (underscore) method or one of the two aliases defined for it - <code>expect</code> or <code>value</code>.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Minitest</span><span class="o">::</span><span class="no">Expectation</span>
</span><span class='line'>  <span class="n">alias_method</span> <span class="ss">:must</span><span class="p">,</span> <span class="ss">:must_be</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">describe</span> <span class="s2">&quot;Lebowski&quot;</span><span class="p">,</span> <span class="s2">&quot;new syntax&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">let</span><span class="p">(</span><span class="ss">:the_dude</span><span class="p">)</span>  <span class="p">{</span> <span class="no">Lebowski</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s2">&quot;Jeffrey&quot;</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should abide&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">_</span><span class="p">(</span><span class="n">the_dude</span><span class="p">)</span><span class="o">.</span><span class="n">must</span> <span class="ss">:abide?</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="n">the_dude</span><span class="p">)</span><span class="o">.</span><span class="n">must</span> <span class="ss">:abide?</span>
</span><span class='line'>    <span class="n">value</span><span class="p">(</span><span class="n">the_dude</span><span class="p">)</span><span class="o">.</span><span class="n">must</span> <span class="ss">:abide?</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Why the change?</h2>

<p>The fact that expectations have been patched directly into core objects has been a source of (mostly unjustified) gripes for years now, and while this change resolves those complaints, they weren&rsquo;t the reason for it.  To understand that, we need to look at how an assertion becomes an expectation.</p>

<p>As I outlined in <a href="http://chriskottom.com/blog/2014/08/customize-minitest-assertions-and-expectations/">Customizing Minitest Assertions and Expectations</a> a few months back, every expectation has an assertion underlying it, and every assertion is an instance method of Minitest::Test, and the framework provided the <code>infect_an_assertion</code> method to map the old assertion method to the new expectation method.</p>

<figure class='code'><figcaption><span>minitest/spec.rb</span><a href='https://github.com/seattlerb/minitest/blob/d863ac2d02d0efcbe73e8e2f6d3b6a22da20ca91/lib/minitest/spec.rb'>link </a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Module</span> <span class="c1"># :nodoc:</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">infect_an_assertion</span> <span class="n">meth</span><span class="p">,</span> <span class="n">new_name</span><span class="p">,</span> <span class="n">dont_flip</span> <span class="o">=</span> <span class="kp">false</span> <span class="c1"># :nodoc:</span>
</span><span class='line'>    <span class="c1"># warn &quot;%-22p -&gt; %p %p&quot; % [meth, new_name, dont_flip]</span>
</span><span class='line'>    <span class="nb">self</span><span class="o">.</span><span class="n">class_eval</span> <span class="o">&lt;&lt;-</span><span class="no">EOM</span>
</span><span class='line'><span class="sh">      def #{new_name} *args</span>
</span><span class='line'><span class="sh">        case</span>
</span><span class='line'><span class="sh">        when #{!!dont_flip} then</span>
</span><span class='line'><span class="sh">          Minitest::Spec.current.#{meth}(self, *args)</span>
</span><span class='line'><span class="sh">        when Proc === self then</span>
</span><span class='line'><span class="sh">          Minitest::Spec.current.#{meth}(*args, &amp;self)</span>
</span><span class='line'><span class="sh">        else</span>
</span><span class='line'><span class="sh">          Minitest::Spec.current.#{meth}(args.first, self, *args[1..-1])</span>
</span><span class='line'><span class="sh">        end</span>
</span><span class='line'><span class="sh">      end</span>
</span><span class='line'><span class="no">    EOM</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>In each case, invoking an expectation ultimately calls an assertion (with the name <code>meth</code>) on the <em>currently running instance of Minitest::Spec</em>.  This method is just an accessor for a thread-local variable that holds a reference to each Minitest::Spec instance within Thread where it runs, but without that reference, there&rsquo;s no target for the assertion method call.</p>

<p>This approach works just fine in most cases, but it has a tendency to blow up when the test needs to create a new Thread and attempts to run expectations within it.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="s2">&quot;Equality&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;doesn&#39;t work inside new Threads&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="mi">1</span><span class="o">.</span><span class="n">must_equal</span> <span class="mi">1</span>       <span class="c1"># passes</span>
</span><span class='line'>  
</span><span class='line'>    <span class="n">t</span> <span class="o">=</span> <span class="no">Thread</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span>
</span><span class='line'>      <span class="mi">1</span><span class="o">.</span><span class="n">must_equal</span> <span class="mi">1</span>     <span class="c1"># raises NoMethodError           </span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>    <span class="n">t</span><span class="o">.</span><span class="n">join</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The first expectation above passes as expected because it executes within a Thread that has access to the thread-local variable.  The second expectation, however, executes within the newly created Thread which doesn&rsquo;t have access to that reference since thread-local variables are not copied from parent Threads to children.  As a result, <code>Minitest::Spec.current</code> returns <code>nil</code>, and the subsequent call to the related assertion (<code>assert_equal</code> in this case) raises a <em>NoMethodError</em>.</p>

<p>The new version of <code>infect_an_assertion</code> addresses the problem by using a new instance of the Minitest::Expectation class as an intermediary between the expectation and the assertion so that there&rsquo;s always a consistent reference back to the current spec.</p>

<figure class='code'><figcaption><span>minitest/spec.rb</span><a href='https://github.com/seattlerb/minitest/blob/9e78cc974f3ef0d9716f1cca2675753cf5f648d0/lib/minitest/spec.rb'>link </a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Module</span> <span class="c1"># :nodoc:</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">infect_an_assertion</span> <span class="n">meth</span><span class="p">,</span> <span class="n">new_name</span><span class="p">,</span> <span class="n">dont_flip</span> <span class="o">=</span> <span class="kp">false</span> <span class="c1"># :nodoc:</span>
</span><span class='line'>    <span class="c1"># warn &quot;%-22p -&gt; %p %p&quot; % [meth, new_name, dont_flip]</span>
</span><span class='line'>    <span class="nb">self</span><span class="o">.</span><span class="n">class_eval</span> <span class="o">&lt;&lt;-</span><span class="no">EOM</span>
</span><span class='line'><span class="sh">      def #{new_name} *args</span>
</span><span class='line'><span class="sh">        Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args)</span>
</span><span class='line'><span class="sh">      end</span>
</span><span class='line'><span class="no">    EOM</span>
</span><span class='line'>
</span><span class='line'>    <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Expectation</span><span class="o">.</span><span class="n">class_eval</span> <span class="o">&lt;&lt;-</span><span class="no">EOM</span><span class="p">,</span> <span class="bp">__FILE__</span><span class="p">,</span> <span class="bp">__LINE__</span> <span class="o">+</span> <span class="mi">1</span>
</span><span class='line'><span class="sh">      def #{new_name} *args</span>
</span><span class='line'><span class="sh">        case</span>
</span><span class='line'><span class="sh">        when #{!!dont_flip} then</span>
</span><span class='line'><span class="sh">          ctx.#{meth}(target, *args)</span>
</span><span class='line'><span class="sh">        when Proc === target then</span>
</span><span class='line'><span class="sh">          ctx.#{meth}(*args, &amp;target)</span>
</span><span class='line'><span class="sh">        else</span>
</span><span class='line'><span class="sh">          ctx.#{meth}(args.first, target, *args[1..-1])</span>
</span><span class='line'><span class="sh">        end</span>
</span><span class='line'><span class="sh">      end</span>
</span><span class='line'><span class="no">    EOM</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>How does this affect you?</h2>

<p>The changes will be phased in over time and across several releases.  Right now, using the old syntax doesn&rsquo;t produce any deprecation warnings, so you&rsquo;ll have some time to get used to the change.  Some time before version 6.0 drops, the old syntax will be deprecated and the monkeypatches on Module will be removed, so if you&rsquo;ve got a lot of Minitest suites, it might be a good idea to get started on the conversions sooner than later.</p>

<p>Whether you&rsquo;re using the new syntax or the old though, the underlying implementation will change, and it&rsquo;s clear that this new approach will cause more objects to be instantiated in order to run the same tests.  Since a lot of Minitest&rsquo;s edge over competitors in performance and memory usage has been the result of creating fewer instances, we may start to see some erosion of that advantage, though the differences probably won&rsquo;t be significant for most test suites.</p>

<h3>Resources:</h3>

<ul>
<li><a href="http://chriskottom.com/blog/2014/08/customize-minitest-assertions-and-expectations/">Customize Minitest Assertions and Expectations</a> - understand the assertion-expectation connection</li>
<li><a href="https://github.com/seattlerb/minitest/issues/337">Spec-inflected assertions raise NoMethodError in child threads</a> - first issue about Threads within tests</li>
<li><a href="https://github.com/seattlerb/minitest/commit/9e78cc974f3ef0d9716f1cca2675753cf5f648d0">Added Minitest::Expectation value monad.</a> - the GitHub commit reference introducing the new syntax</li>
<li><a href="http://blog.zenspider.com/blog/2015/04/great-expectations.html">Great Expectations</a> - Ryan Davis&#8217; blog post about the new syntax</li>
<li><a href="http://www.imdb.com/title/tt0118715/">The Big Lebowski</a> - You haven&rsquo;t seen this!?!  Stop whatever you&rsquo;re doing and go watch it.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Testing Ruby Mixins in Isolation]]></title>
    <link href="http://chriskottom.com/blog/2015/03/testing-ruby-mixins-in-isolation/"/>
    <updated>2015-03-06T08:29:52+01:00</updated>
    <id>http://chriskottom.com/blog/2015/03/testing-ruby-mixins-in-isolation</id>
    <content type="html"><![CDATA[<p>Ruby&rsquo;s approach to inheritance by module inclusion isn&rsquo;t unique in the world of programming languages, but it gets a lot of attention and hits a sweet spot for a lot of use cases.  Finding the right patterns to test them, though, has been a challenge for many because, as mixins, they tend to get&hellip; You know&hellip; mixed into things.  Testing something that can&rsquo;t be instantiated on its own requires a little consideration and different treatment than a standard class, so a lot of programmers resort to testing the inherited behaviors in each including class or, only slightly better, using shared helpers or RSpec shared examples.</p>

<p>All of these techniques have their place in testing, but in a perfect world, they&rsquo;re not the tools that you should reach for as a first option.  Ideally you&rsquo;re first making a good-faith effort at testing your mixins, to the greatest possible degree, in isolation from the classes that include them.</p>

<p>For the purposes of this discussion, there are two types of mixins we’re concerned with: those that are coupled with the classes that include them, and those that aren&rsquo;t.  And as you might imagine, non-coupled modules are easier to test than their coupled cousins, even though the patterns used in each case are similar.</p>

<h2>Non-Coupled Mixins</h2>

<p>Suppose you have a simple mixin that allows instances of the extended class to shout out a generic greeting.</p>

<figure class='code'><figcaption><span>lib/greetable.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Greetable</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">greet</span>
</span><span class='line'>    <span class="nb">print</span> <span class="s1">&#39;Ohai!&#39;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This module doesn&rsquo;t rely on any state or methods of the included class to do its job - it&rsquo;s non-coupled.  You may have several classes that include this mixin, but rather than duplicate the same tests for each of them, you can test the functionality in isolation by creating an Object instance and extending it directly with the Greetable module.</p>

<figure class='code'><figcaption><span>test/greetable_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">GreetableTest</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Test</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">setup</span>
</span><span class='line'>    <span class="vi">@greetable</span> <span class="o">=</span> <span class="no">Object</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>    <span class="vi">@greetable</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="no">Greetable</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_greeting_delivered</span>
</span><span class='line'>    <span class="n">assert_output</span> <span class="s1">&#39;Ohai!&#39;</span> <span class="k">do</span>
</span><span class='line'>      <span class="vi">@greetable</span><span class="o">.</span><span class="n">greet</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>By extending the Object instance, we&rsquo;re getting the simplest possible Greetable we can, and we&rsquo;ve managed to do it without re-opening the Object class.</p>

<h2>Coupled Mixins</h2>

<p>Suppose instead you&rsquo;d like to let Greetable be a little more familiar with the included class.  In cases where the receiver has a <code>name</code> attribute, Greetable should deliver a personal greeting instead of the generic one like so:</p>

<figure class='code'><figcaption><span>lib/greetable.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Greetable</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">greet</span>
</span><span class='line'>    <span class="k">if</span> <span class="nb">self</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
</span><span class='line'>      <span class="nb">print</span> <span class="s2">&quot;Hey, </span><span class="si">#{</span> <span class="nb">self</span><span class="o">.</span><span class="n">name</span> <span class="si">}</span><span class="s2">.&quot;</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>      <span class="nb">print</span> <span class="s1">&#39;Ohai!&#39;</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>You&rsquo;ll need to extend the test case to cover this new wrinkle.  Specifically, you&rsquo;ll want to add a new test that will check that a Greetable with a <code>name</code> method uses it in formatting the greeting.  It would be simple enough to use a technique similar to the one you used earlier, although in this case you might want to change the structure just a bit.</p>

<figure class='code'><figcaption><span>test/greetable_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">GreetableTest</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Test</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_personalized_greeting_delivered</span>
</span><span class='line'>    <span class="vi">@greetable</span> <span class="o">=</span> <span class="no">Object</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>  <span class="vi">@greetable</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="no">Greetable</span><span class="p">)</span>
</span><span class='line'>  
</span><span class='line'>    <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="vi">@greetable</span>
</span><span class='line'>      <span class="k">def</span> <span class="nf">name</span>
</span><span class='line'>        <span class="s1">&#39;Matz&#39;</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">assert_output</span><span class="p">(</span><span class="s1">&#39;Hey, Matz.&#39;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="vi">@greetable</span><span class="o">.</span><span class="n">greet</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_generic_greeting_delivered</span>
</span><span class='line'>    <span class="vi">@greetable</span> <span class="o">=</span> <span class="no">Object</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>    <span class="vi">@greetable</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="no">Greetable</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">assert_output</span> <span class="s1">&#39;Ohai!&#39;</span> <span class="k">do</span>
</span><span class='line'>      <span class="vi">@greetable</span><span class="o">.</span><span class="n">greet</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Here you start with a vanilla Object instance and extend it with the Greetable module, same as before, but in this case, you also need to define <code>name</code> as a <em>singleton method</em> on the Object as well.  Just as the name implies, this is a method that belongs <em>only to this instance</em>, and it&rsquo;s just enough to meet the minimum criteria needed to test the new personalized greeting behavior.</p>

<p>This works just fine, but some might find it unnecessarily complicated or be turned off by the metaprogramming tricksiness.  Fortunately, there&rsquo;s another method that&rsquo;s simpler to understand and involves less monkeypatching, and that&rsquo;s to use a Ruby Struct.</p>

<figure class='code'><figcaption><span>test/greetable_test.rb </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;test_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">GreetableTest</span> <span class="o">&lt;</span> <span class="ss">Minitest</span><span class="p">:</span><span class="ss">:Test</span>
</span><span class='line'>  <span class="no">ThingWithName</span> <span class="o">=</span> <span class="no">Struct</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="kp">include</span> <span class="no">Greetable</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">test_personalized_greeting_delivered</span>
</span><span class='line'>    <span class="n">greetable</span> <span class="o">=</span> <span class="no">ThingWithName</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Matz&#39;</span><span class="p">)</span>
</span><span class='line'>  
</span><span class='line'>    <span class="n">assert_output</span><span class="p">(</span><span class="s1">&#39;Hey, Matz.&#39;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">greetable</span><span class="o">.</span><span class="n">greet</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>In this case, you define a new ThingWithName class just for this test case using <code>Struct.new</code> which looks like a constructor but actually returns a Ruby Class.  The instances of this class will have whatever list of attributes you passed to <code>Struct.new</code> - in this case, a name.  This method also takes an optional block argument which, when present, is evaluated within the context of the returned Class.  Once you get into the body of the test, you only need to instantiate a new ThingWithName instance and pass it a String <code>:name</code> argument.</p>

<p>Clearly these are simple examples and only scratch the surface of what you might encounter in your own day-to-day work, but they&rsquo;re a great example of how mixing the simplicity of the Minitest framework with good, old-fashioned Ruby know-how can solve a potentially thorny problem.</p>
]]></content>
  </entry>
  
</feed>
