<div class="single">
  <!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.18.1" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
    <link rel='stylesheet' href='//fonts.googleapis.com/css?family=Open+Sans|Marcellus+SC'>
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/solarized_dark.min.css">
    <link rel="stylesheet" href="/css/styles.css">
    <link rel="stylesheet" href="/css/custom.css">
    <link rel="alternate" type="application/rss+xml" title="RSS" href="http://chrisholtz.com//index.xml">

    
    <title>Service object test strategies - Chris Holtz</title>
    <meta property='og:title' content="Service object test strategies - Chris Holtz">
    <meta property="og:type" content="article">
    

    <meta property="og:url" content="http://chrisholtz.com/blog/service-object-test-strategies/">
    
    <meta property="og:image" content="http://chrisholtz.com/images/chess.png">

    
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-16429498-2', 'auto');
ga('send', 'pageview');
</script>

  </head>

  <body>

    <header class="site">
      <div class="title"><a href="http://chrisholtz.com/">Chris Holtz</a></div>
    </header>

    <div class="container site">


  <div class="row">
    <div class="col-sm-9">

      <article class="single" itemscope="itemscope" itemtype="http://schema.org/Article">

        <meta itemprop="mainEntityOfPage"  itemType="https://schema.org/WebPage" content="http://chrisholtz.com/"/>
        <meta itemprop="dateModified" content="2016-05-11T17:00:00&#43;00:00">
        <meta itemprop="headline" content="Service object test strategies">
        <meta itemprop="description" content="Previously,  we looked at service objects: what are they, how can they clean up controllers and models, and how they can better organize your Rails project. Next we&rsquo;ll see how service objects simplify unit tests and can speed up your test suite.
">
        <meta itemprop="url" content="http://chrisholtz.com/blog/service-object-test-strategies/">
        <div itemprop="image" itemscope itemtype="https://schema.org/ImageObject">
          <meta itemprop="url" content="http://chrisholtz.com/images/chess.png" />
          <meta itemprop="width" content="800">
          <meta itemprop="height" content="800">
        </div>
        <div itemprop="publisher" itemscope itemtype="https://schema.org/Organization">
          <div itemprop="logo" itemscope itemtype="https://schema.org/ImageObject">
            <meta itemprop="url" content="http://chrisholtz.com/images/logo.jpg">
            <meta itemprop="width" content="100">
            <meta itemprop="height" content="100">
          </div>
          <meta itemprop="name" content="Chris Holtz">
        </div>
        <div itemprop="author" itemscope itemtype="https://schema.org/Person">
          <meta itemprop="name" content="">
        </div>

        <div class="image" style="background-image: url(http://chrisholtz.com/images/chess.png);"></div>
        <div class="image-credit"><a href="https://www.flickr.com/photos/edith_soto/" target="window">Image credit: https://www.flickr.com/photos/edith_soto/</a></div>

        <header class="article-header">
          
          <h1 class="article-title">Service object test strategies</h1>
        </header>

        <div class="article-body" itemprop="articleBody">
          <p>Previously,  we looked at service objects: what are they, how can they clean up controllers and models, and how they can better organize your Rails project. Next we&rsquo;ll see how service objects simplify unit tests and can speed up your test suite.
</p>

<p>This is a multi-part series:</p>

<ul>
<li><a href="/blog/organize-your-app-with-service-objects">Part I: Organize your app with service objects</a></li>
<li><a href="/blog/service-object-test-strategies">Part II: Service Object Test Strategies</a></li>
</ul>

<h2 id="starting-point">Starting Point</h2>

<p>Let&rsquo;s begin with something similar to <a href="/blog/organize-your-app-with-service-objects">Part I</a>. When an administrator creates a new user account, other admins will receive either an email or an SMS notification. All of the logic is inside of the <code>User</code> model.</p>

<pre><code># app/models/user.rb
class User &lt; ActiveRecord::Base
  messageable_user = -&gt; (field, exclude){
    relation = where(&quot;#{field} is not null&quot;)
    relation = relation.where(&quot;#{field} &lt;&gt; ?&quot;, exclude[field]) if exclude.present?
    relation
  }

  scope :emailable_users, messageable_user.curry.call('email_address')
  scope :textable_users,  messageable_user.curry.call('phone_number')

  after_create :notify_users

  private

  def notify_users
    User.emailable_users(self).each do |recipient|
      UserMailer.notify_users(recipient: recipient, new_user: self).deliver_now
    end

    User.textable_users(self).each do |recipient|
      send_text recipient: recipient, new_user: self
    end
  end

  def send_text(recipient: , new_user: )
    # This is a call to a fictional SMS service
    TextMessageApi.send_message recipient.phone_number, &quot;A new user has been created: #{new_user.email_address}&quot;
  end
end
</code></pre>

<p>The scopes may look odd to you, but don&rsquo;t be concerned - if you are unfamiliar with the <a href="http://ruby-doc.org/core-2.3.0/Method.html#method-i-curry" target = "window">curry</a> method, it translates a function that takes multiple arguments into a sequence of of functions, each with a single argument. For example:</p>

<pre><code>add      = -&gt; (first, second) { first + second }
function = add.curry
results1 = function.call(1, 2)
results2 = function.call(1).call(2)
results1 == results2
=&gt; true
</code></pre>

<p>This contrived example has limited usefulness, but you can see in the <code>User</code> model that <code>curry</code> is used to apply the same lambda function to multiple scopes.</p>

<h2 id="first-draft-tests">First Draft Tests</h2>

<p>As discussed in <a href="/blog/organize-your-app-with-service-objects">Part I</a>, there are problems with this code. Multiple concerns are combined into one location - this impacts the corresponding unit tests. All of the associated test logic is in <code>test/unit/user_test.rb</code>.</p>

<pre><code>require_relative '../test_helper'

class UserTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }
  end

  context 'scopes' do
    should 'return all users that receive email notifications' do
      assert_equal 3, User.emailable_users(nil).length
    end

    should 'return all users that receive sms notifications' do
      assert_equal 5, User.textable_users(nil).length
    end
  end

  context 'notifications' do
    should 'send email notifications on user create' do
      ActionMailer::Base.deliveries = []
      FactoryGirl.create :user, email_address: &quot;test@test.com&quot;

      assert_equal 3, ActionMailer::Base.deliveries.length
    end

    should 'send sms notifications on user create' do
      TextMessageApi.deliveries = []
      FactoryGirl.create :user, phone_number: &quot;999-9999&quot;

      assert_equal 5, TextMessageApi.deliveries.length
    end
  end
end
</code></pre>

<p><span style="color: #aaa; font-size: .9em;">All test examples are built with minitest and use the <a style="color: #aaa;" href="https://github.com/thoughtbot/shoulda-context" target="window">shoulda-context</a> gem. However, the principals apply equally well to other unit test frameworks.</span></p>

<p>Like the original code this file tests, there are several problems:</p>

<ol>
<li>Callbacks force us to test side-effects of operations rather than isolating tests to specific behavior</li>
<li>Potentially complex data setup is required to test messaging</li>
<li>Single-responsibility tests are hard to write</li>
</ol>

<p>Having just written these unit tests, I can say first-hand that this was a pain in the neck - with special emphasis on indirectly testing message counts based on callbacks generated on the creation of a new user.</p>

<p>By splitting the user logic into individual services, the unit tests become much more direct - tests focus on the behavior of the service object instead of tangentially related data.</p>

<h2 id="second-draft">Second Draft</h2>

<p>Let&rsquo;s rearrange the <code>User</code> model code into a few services: <code>SendSmsMessage</code>, <code>NotifyUsers</code>, and <code>CreateUser</code>.</p>

<h3 id="user-model">User Model</h3>

<pre><code># app/models/user.rb
class User &lt; ActiveRecord::Base
  messageable_user = -&gt; (field, exclude){
    relation = where(&quot;#{field} is not null&quot;)
    relation = relation.where(&quot;#{field} &lt;&gt; ?&quot;, exclude[field]) if exclude.present?
    relation
  }.curry

  scope :emailable_users, messageable_user.call('email_address')
  scope :textable_users,  messageable_user.call('phone_number')
end
</code></pre>

<p>The trimmed-down user model is much cleaner - the logic is concerned only with user data. Note: the curry call was moved to the end of the lambda declaration - no need to call it  every time we define a scope.</p>

<pre><code># test/models/user_test.rb
require_relative '../test_helper'

class UserTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }
  end

  context 'scopes' do
    should 'return all users that receive email notifications' do
      assert_equal 3, User.emailable_users(exclude = nil).length
    end

    should 'return all users that receive sms notifications' do
      assert_equal 5, User.textable_users(exclude = nil).length
    end
  end
end
</code></pre>

<p>The tests are also simplified. With the callback removed, the tests aren&rsquo;t concerned with notification counts that are dependent on the creation of new user records.</p>

<h3 id="send-sms-message-service">Send SMS Message Service</h3>

<pre><code># app/services/send_sms_message.rb
module Services
  class SendSmsMessage
    include Services::Base

    def call(phone_number, message)
      TextMessageApi.send_message phone_number, message
    end
  end
end
</code></pre>

<p>The <code>SendSmsMessage</code> service really doesn&rsquo;t do much - it is a glorified wrapper around the text message API. Though it doesn&rsquo;t seem like much of a win, the service centralizes all SMS activity which makes it much easier to change SMS providers that may contain differing APIs.</p>

<pre><code># test/services/send_sms_message_test.rb
require_relative '../test_helper'

class SendSmsTextTest &lt; ActiveSupport::TestCase
  setup do
    TextMessageApi.deliveries = []
  end

  should 'send a message to the specified phone number' do
    Services::SendSmsMessage.call '555-555-5555', 'test message'
    assert_equal 1, TextMessageApi.deliveries.length
  end
end
</code></pre>

<p>The corresponding test file is equally simple. However, it has much the same problem as the user_test.rb file from the first draft - this test makes a call to an external service. At best, this significantly slows down the test suite run time. At worst, the the API call sends SMS messages every time the test file is run. As we&rsquo;ll see next, the same problem applies to the <code>NotifyUsers</code> service.</p>

<h3 id="notify-users-service">Notify Users Service</h3>

<pre><code># app/services/notify_users.rb
module Services
  class NotifyUsers
    include Services::Base

    def call(new_user)
      User.emailable_users(exclude = new_user).each do |recipient|
        UserMailer.notify_users(recipient: recipient, new_user: new_user).deliver_now
      end

      User.textable_users(exclude = new_user).each do |recipient|
        Services::SendSmsMessage.call recipient.phone_number, &quot;A new user has been created: #{new_user.email_address}&quot;
      end
    end
  end
end
</code></pre>

<p>The <code>NotifyUsers</code> service is no longer dependent on the creation of a user record and is accessible anywhere in the project</p>

<pre><code># test/services/notify_users_test.rb
require_relative '../test_helper'

class NotifyUsersTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }

    TextMessageApi.deliveries     = []
    ActionMailer::Base.deliveries = []

    new_user = FactoryGirl.create :user, email_address: &quot;test@test.com&quot;, phone_number: &quot;999-9999&quot;
    Services::NotifyUsers.call new_user
  end

  should 'send email notifications' do
    assert_equal 3, ActionMailer::Base.deliveries.length
  end

  should 'send sms notifications' do
    assert_equal 5, TextMessageApi.deliveries.length
  end
end

</code></pre>

<p>This test file has the same problem as the first draft tests - test are verified by counting the sms messages sent - these counts aren&rsquo;t directly related to the <code>NotifyUser</code> code, but rather the <code>SendSmsMessage</code> service it depends on. We&rsquo;ll address that in the next step.</p>

<h3 id="create-user-service">Create User Service</h3>

<pre><code># app/services/create_user.rb
module Services
  class CreateUser
    include Services::Base

    def call(params)
      user = User.create params
      Services::NotifyUsers.call user if user.valid?
      user
    end
  end
end
</code></pre>

<p>The <code>CreateUser</code> service replaces the original callback work flow by creating a new user record and sending notification messages.</p>

<pre><code># test/services/create_user_test.rb
require_relative '../test_helper'

class CreateUserTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }

    TextMessageApi.deliveries     = []
    ActionMailer::Base.deliveries = []

    params = {
      username:      'username',
      email_address: 'test@test.com',
      phone_number:  '555-555-5555'
    }

    @user = Services::CreateUser.call params
  end

  should 'create a new user' do
    assert @user.valid?, 'A valid user should have been created'
  end

  should 'send sms and email notifications' do
    assert_equal 3, ActionMailer::Base.deliveries.length
    assert_equal 5, TextMessageApi.deliveries.length
  end
end

</code></pre>

<p>Like the <code>NotifyUsers</code> test file, these tests also rely on the results of dependent services to validate the correct behavior.</p>

<h2 id="third-draft-tests">Third Draft Tests</h2>

<p>The latest round of changes improved the logic by splitting it into composable pieces; sort of like rearrangeable Lego blocks. However, the corresponding unit tests still have an issue to be ironed out. The remote calls to the SMS API are problematic: they are slow and result in actual sent messages.</p>

<p>To illustrate the problem, we&rsquo;ll update the <code>SendSmsMessage</code> service to print a message to the console declaring that an sms text has been sent.</p>

<pre><code># app/services/send_sms_message.rb
module Services
  class SendSmsMessage
    include Services::Base

    def call(phone_number, message)
      TextMessageApi.send_message phone_number, message
      puts '*** Remote Call'
    end
  end
end
</code></pre>

<p>When we run <code>rake test</code> the output looks like this:</p>

<pre><code>..*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
.*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
.*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
.*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
*** Remote Call
.*** Remote Call
.
</code></pre>

<p>This is pretty bad - over twenty sms texts are sent by running the test suite. Not only are users potentially being spammed, remote calls take <em>time to run</em>. If you replace the <code>puts</code> statement with <code>sleep 1</code> to simulate a round trip to a remote server, the test suite becomes unbearably slow.</p>

<h2 id="dependency-injection">Dependency Injection</h2>

<p>To address this, we can introduce dependency injection into the tests. This is a decidedly mockist approach, but it keeps tests centered on project code, rather on results returned from remote dependencies outside the project.</p>

<p>There are a number of ways to do this - I&rsquo;ll illustrate a couple approaches using the <code>NotifyUsers</code> service. Here it is again:</p>

<pre><code>module Services
  class NotifyUsers
    include Services::Base

    def call(new_user)
      User.emailable_users(exclude = new_user).each do |recipient|
        UserMailer.notify_users(recipient: recipient, new_user: new_user).deliver_now
      end

      User.textable_users(exclude = new_user).each do |recipient|
        Services::SendSmsMessage.call recipient.phone_number, &quot;A new user has been created: #{new_user.email_address}&quot;
      end
    end
  end
end
</code></pre>

<p>The supporting unit tests for this file counts the number of sms messages sent, but notice that this service doesn&rsquo;t directly send those messages - that job is handled by the <code>SendSmsMessage</code> service.</p>

<p>First thing we&rsquo;ll do is update the <code>NotifyUsers</code> service so that we can override the <code>SendSmsMessage</code> service with the class of our choosing:</p>

<pre><code>module Services
  class NotifyUsers
    include Services::Base

    def initialize(send_sms_service = Services::SendSmsMessage)
      @send_sms_service = send_sms_service
    end

    def call(new_user)
      User.emailable_users(exclude = new_user).each do |recipient|
        UserMailer.notify_users(recipient: recipient, new_user: new_user).deliver_now
      end

      User.textable_users(exclude = new_user).each do |recipient|
        @send_sms_service.call recipient.phone_number, &quot;A new user has been created: #{new_user.email_address}&quot;
      end
    end
  end
end
</code></pre>

<p>Rather than call the <code>SendSmsMessage</code> service directly, an instance variable is set in the <code>initialize()</code> method. This instance variable is used in the <code>call</code> method to make the SMS call.</p>

<p>The unit tests are modified to define a fake/mock class that is passed to the <code>NotifyUsers</code> service during initialization.</p>

<pre><code>require_relative '../test_helper'

class NotifyUsersTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }

    TextMessageApi.deliveries     = []
    ActionMailer::Base.deliveries = []

    new_user = FactoryGirl.create :user, email_address: &quot;test@test.com&quot;, phone_number: &quot;999-9999&quot;

    # Mock sms service is injected into the NotifyUsers service
    @message_service = MockSendSmsMessage.new
    @service         = Services::NotifyUsers.new(@message_service)

    @service.call new_user
  end

  should 'send email notifications' do
    assert_equal 3, ActionMailer::Base.deliveries.length
  end

  should 'send sms notifications' do
    # Instead of counting the message deliveries made, we count the fake
    # deliveries accumulated by the mock object
    assert_equal 5, @message_service.deliveries.length
  end

  # Simulate the SendSmsMessage object
  class MockSendSmsMessage
    attr_accessor :deliveries

    def call(phone_number, message)
      @deliveries ||= []
      @deliveries &lt;&lt; message
    end
  end
end
</code></pre>

<p>Notice the <code>MockSendSmsMessage</code> class at the bottom of this file - it accumulates message calls. This count is later referenced in the tests rather than the deliveries made by the actual <code>SendSmsMessage</code> service. Because the original service isn&rsquo;t called, we don&rsquo;t need to worry about inadvertently spamming people with text messages. Also, because sms messages aren&rsquo;t sent, the tests run quite quickly.</p>

<h3 id="mocha-gem">Mocha Gem</h3>

<p>Rather than build mock objects by hand and managing dependency injection details, another approach is to use a mocking/stubbing library. Rspec comes with this out-of-the-box and  minitest can gain the same capabilities with the <a href="https://rubygems.org/gems/mocha" target="window">Mocha Gem</a>. Start by adding <code>Gem 'mocha'</code> to your Gemfile, then require it in <code>test_helper.rb</code></p>

<pre><code># test/test_helper.rb

...

require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

# Add these two lines
require 'minitest/unit'
require 'mocha/mini_test'

...
</code></pre>

<p>The mocha version of the test file looks like this:</p>

<pre><code>require_relative '../test_helper'

class NotifyUsersTest &lt; ActiveSupport::TestCase
  setup do
    (1..3).each{ |n| FactoryGirl.create :user, email_address: &quot;test#{n}@test.com&quot; }
    (1..5).each{ |n| FactoryGirl.create :user, phone_number:   &quot;#{n}#{n}#{n}-#{n}#{n}#{n}#{n}&quot; }

    TextMessageApi.deliveries     = []
    ActionMailer::Base.deliveries = []

    @new_user = FactoryGirl.create :user, email_address: &quot;test@test.com&quot;, phone_number: &quot;999-9999&quot;
  end

  should 'send email notifications' do
    Services::NotifyUsers.call @new_user
    assert_equal 3, ActionMailer::Base.deliveries.length
  end

  should 'send sms notifications' do
    Services::SendSmsMessage.expects(:call).times(5)
    Services::NotifyUsers.call @new_user
  end
end
</code></pre>

<p>This is more concise than the previous version - we define the expectation just before the service call. The <code>expects</code> method both stubs <code>call()</code> as well as defines how it expects <code>call()</code> to be handled. In this case, it should be called five times. There are <a href="http://gofreerange.com/mocha/docs/Mocha/Expectation.html" target="window">quite a few</a> options available to this API.</p>

<p>While this approach allows for much more terse test code, it forces you to have an understanding of how a class works under the hood. Should I know (or care) that <code>Services::NotifyUsers</code> calls <code>Services::SendSmsMessage</code>? Not really. That is the responsibility of the of the <code>NotifyUsers</code> class, while our tests should be concerned purely with its inputs and outputs.</p>

<p>Further, when pushed to the limits, this sort of test can become fragile. What if the <code>NotifyUsers</code> implementation changes such that it no longer calls the <code>SendSmsMessage</code> service? One wouldn&rsquo;t necessarily know to update the corresponding tests.</p>

<p>The same could be argued about the dependency injection approach. The difference - and this is somewhat semantic - is that with dependency injection the dependency is raised to the service&rsquo;s <code>initialize()</code> method signature. If the internals of the service change, the <code>initialize()</code> method would change as well, making it plainly obvious that the dependent tests would need to change too.</p>

<p>Ultimately, it is up to you to decide which approach to use. Both have their advantages and draw-backs.</p>

<h2 id="conclusion">Conclusion</h2>

<p>This somewhat lengthy unit test exploration has shown that:</p>

<ol>
<li>Moving monolithic code into logical chunks results in smaller reusable objects</li>
<li>Service objects can lead to more code, but better tested code</li>
<li>External dependencies can in some cases lead to undesirable side-effects</li>
<li>Dependency injection removes external API execution from the test logic</li>
<li>Dependency injection can make tests run faster</li>
<li>Mock/stub libraries may be a viable alternative to dependency injection within unit tests</li>
</ol>

<p>Thank you for sticking with me through this. Please feel free to add your comments below; I&rsquo;d love to hear what you think.</p>
        </div>


        <aside>
          

          <div class="section share">
            <a href="http://www.facebook.com/sharer.php?src=bm&u=http%3a%2f%2fchrisholtz.com%2fblog%2fservice-object-test-strategies%2f&t=Service%20object%20test%20strategies" onclick="window.open(this.href, 'PCwindow', 'width=550, height=350, menubar=no, toolbar=no, scrollbars=yes'); return false;"><i class="fa fa-facebook"></i></a>
            <a href="http://twitter.com/intent/tweet?url=http%3a%2f%2fchrisholtz.com%2fblog%2fservice-object-test-strategies%2f&text=Service%20object%20test%20strategies&tw_p=tweetbutton" onclick="window.open(this.href, 'PCwindow', 'width=550, height=350, menubar=no, toolbar=no, scrollbars=yes'); return false;"><i class="fa fa-twitter"></i></a>
            <a href="https://plus.google.com/share?url=http%3a%2f%2fchrisholtz.com%2fblog%2fservice-object-test-strategies%2f" onclick="window.open(this.href, 'PCwindow', 'width=550, height=350, menubar=no, toolbar=no, scrollbars=yes'); return false;"><i class="fa fa-google-plus"></i></a>
            <a href="http://getpocket.com/edit?url=http%3a%2f%2fchrisholtz.com%2fblog%2fservice-object-test-strategies%2f&title=Service%20object%20test%20strategies" onclick="window.open(this.href, 'PCwindow', 'width=550, height=350, menubar=no, toolbar=no, scrollbars=yes'); return false;"><i class="fa fa-get-pocket"></i></a>
          </div>

          
          
          <div id="disqus_thread"></div>
          <script type="text/javascript">
(function() {
  var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
  var disqus_shortname = 'chrisholtz';
  dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
          </script>
          <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
          <a href="http://disqus.com/" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
          
          
        </aside>

      </article>
    </div>

    <div class="col-sm-3">
      <aside class="site">

  
  <div class="section">
    <header><div class="title">TableOfContents</div></header>
    <div class="list-default"><nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#starting-point">Starting Point</a></li>
<li><a href="#first-draft-tests">First Draft Tests</a></li>
<li><a href="#second-draft">Second Draft</a>
<ul>
<li><a href="#user-model">User Model</a></li>
<li><a href="#send-sms-message-service">Send SMS Message Service</a></li>
<li><a href="#notify-users-service">Notify Users Service</a></li>
<li><a href="#create-user-service">Create User Service</a></li>
</ul></li>
<li><a href="#third-draft-tests">Third Draft Tests</a></li>
<li><a href="#dependency-injection">Dependency Injection</a>
<ul>
<li><a href="#mocha-gem">Mocha Gem</a></li>
</ul></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul></li>
</ul>
</nav></div>
  </div>
  

  

  <div class="section">
    <header><div class="title">LatestPosts</div></header>
    <div class="content">
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/service-object-test-strategies/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/chess.png);"></div>
    <div class="detail">
      
      <h2 class="title">Service object test strategies</h2>
      <div class="summary"><p>Previously,  we looked at service objects: what are they, how can they clean up controllers and models, and how they can better organize your Rails project. Next we&rsquo;ll see how service objects simplify unit tests and can speed up your test suite.
</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/organize-your-app-with-service-objects/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/organize.png);"></div>
    <div class="detail">
      
      <h2 class="title">Organize your app with service objects</h2>
      <div class="summary"></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/switch-git-branch-by-partial-name/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/tree_branches.png);"></div>
    <div class="detail">
      
      <h2 class="title">Switch Git Branches by partial name</h2>
      <div class="summary">If you are building an app with a long history, you may have a lot of git branches laying around. Generally you can use your terminal&rsquo;s auto completion to quickly resolve branch names with minimal typing. However, there may be cases where there are branch names that start with the same characters.
With this git alias, you can search your git branches by partial match; then switch to the first match.</div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/in-defense-of-dynamic-finders/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/aikido2.jpg);"></div>
    <div class="detail">
      
      <h2 class="title">In defense of dynamic finders</h2>
      <div class="summary"><p>Last week I had a discussion with a colleague (and talented ruby developer) about the decision to remove dynamic finders from ActiveRecord. This is old news and I&rsquo;m sure has been hashed to death, but I figured I&rsquo;d chime in with a few thoughts, now that Rails 4.0 is out and we&rsquo;re moving towards 4.1.</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/more-than-you-care-to-know-about-the-uniq-method/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/different.jpg);"></div>
    <div class="detail">
      
      <h2 class="title">More than you care to know about the uniq method</h2>
      <div class="summary"><p>The other day I was digging through the ruby documentation and stumbled on the uniq method. I was startled to find that you can pass in a block as a parameter. My instinct was to back away slowly, not unlike a cat looking at a bathtub full of water.

After all, why on Earth would one want to filter uniqueness based on some criteria other than an exact match? Undaunted, I figured it would be fun to explore this method a bit more&hellip; find out what makes it tick.</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/getting-started-with-the-google-maps-api/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/google_maps.png);"></div>
    <div class="detail">
      
      <h2 class="title">Getting started with the Google Maps API</h2>
      <div class="summary"><p>Recently I had the chance to work with a bunch of zip code and area code data. Each code had an associated latitude and longitude - from a list of area codes, I had to find those  that were N miles from a specific zip code.

Ultimately the solution didn&rsquo;t call for a map-style UI, but I had he opportunity to explore the Google Maps API a bit. Here&rsquo;s a brief overview of the service.</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/lets-make-a-ruby-hash-map-method-that-returns-a-hash-instead-of-an-array/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/ruby_code.png);"></div>
    <div class="detail">
      
      <h2 class="title">Let&#39;s make a Ruby hash map method that returns a hash instead of an array</h2>
      <div class="summary"><p>There&rsquo;s this Ruby problem I revisit from time to time. The built-in hash array has a really handy map method. To the uninitiated, the map method is used to modify all elements in an array with the function specified.</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/upgrade-your-aws-database-disk-space/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/hard_disk.png);"></div>
    <div class="detail">
      
      <h2 class="title">upgrade your aws database disk space</h2>
      <div class="summary"><p>A few years ago, I moved a co-located site over to Amazon Web Services. This included web servers, data base servers, load balancers, etc. At the time I figured an ample 8GB would be sufficient space to house our modest Postgresql database. I was right&hellip; for a time.

Two years after the move, we started to run out of space due to miscellaneous file clutter: database dumps and log files grew. Clearing up this mess helped a bunch, but over time the database itself grew. Now it&rsquo;s too large for the once spacious 8 gig.</p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/installing-postgresql-on-an-aws-ec2-instance/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/default.jpg);"></div>
    <div class="detail">
      
      <h2 class="title">Installing Postgresql on an AWS EC2 instance</h2>
      <div class="summary"><p></p></div>
    </div>
  </a>
</article>
</div>
      
      <div class="sm"><article class="li">
  <a href="http://chrisholtz.com/blog/better-syntax-hints-with-flycheck-mode-and-rubocop/" class="clearfix">
    <div class="image" style="background-image: url(http://chrisholtz.com/images/airplane_wing.png);"></div>
    <div class="detail">
      
      <h2 class="title">better syntax hints with flycheck-mode and rubocop</h2>
      <div class="summary"><p>I&rsquo;ve been using flycheck-mode in emacs for about a month now. Out of the box, it does a great job checking the syntax of my code. As I type, it automatically highlights syntax errors and warnings - it looks something like this:</p>

<p></p></div>
    </div>
  </a>
</article>
</div>
      
    </div>
  </div>

  
  <div class="section taxonomies">
    <header><div class="title">category</div></header>
    <div class="content">
      <a href="http://chrisholtz.com/categories/ruby">ruby</a><a href="http://chrisholtz.com/categories/aws-postgresql">aws-postgresql</a><a href="http://chrisholtz.com/categories/emacs-ruby">emacs-ruby</a><a href="http://chrisholtz.com/categories/javascript-api">javascript-api</a>
    </div>
  </div>
  
  <div class="section taxonomies">
    <header><div class="title">tag</div></header>
    <div class="content">
      
    </div>
  </div>
  

</aside>

    </div>

  </div>

      </div>

    <footer class="site">
      <p>&copy; 2016 Chris Holtz</p>
      <p>Powered by <a href="http://gohugo.io" target="_blank">Hugo</a>,</p>
      <p>Theme <a href="https://github.com/dim0627/hugo_theme_robust" target="_blank">Robust</a> designed by <a href="http://yet.unresolved.xyz" target="_blank">Daisuke Tsuji</a></p>
    </footer>

    <script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
    <script>hljs.initHighlightingOnLoad();</script>

    

  </body>
</html>

</div>
