Toggleable Fakes for better integration testing

During the development of iOS Project Monitor, I ran into the need to test against a few third party services. Engineyard’s Andy Delcambre gave a great talk on how to use test matrices and fake services to write one test that hits both your fake and the service.

Most people leap towards WebMock or VCR to test against services. This is an alternate approach that is a little more upfront work but adds incredible confidence in your code.

Overview

  • Create a FakeThirdParty service.
  require 'sinatra/base'

  class FakePusher < Sinatra::Base
    post "/apps/:app_id/events", provides: :json do
      JSON.parse(request.body.read)
      {}.to_json
    end

    # start the server if ruby file executed directly
    run! if app_file == $0
  end

  class FakeError
    def self.call(env)
      [ 503, { 'Content-Type' => 'application/json' }, [{ "error" => "server error" }.to_json] ]
    end
  end

  class FakeUnauthorized
    def self.call(env)
      [ 401, { 'Content-Type' => 'application/json' }, [{"error"=>"unauthorized"}.to_json] ]
    end
  end

  
  • Using WebMock, route all traffic to www.thirdparty.com to our sinatra fake. Take note of the .to_rack method:
  require 'webmock/rspec'

  module FakeSpecHelpers
    def servers_return_healthy
      puts "WARNING: Stubbing out healthy servers"
      WebMock.stub_request(:any, /.*api.pusherapp.com\/.*/).to_rack(FakePusher)
    end

    def servers_return_error
      WebMock.stub_request(:any, /.*/).to_rack(FakeError)
    end

    def servers_return_unauthorized
      WebMock.stub_request(:any, /.*/).to_rack(FakeUnauthorized)
    end
  end

  RSpec.configure do |config|
    config.include FakeSpecHelpers

    config.before(:each) do
      if ENV["INTEGRATION"] == "true"
        WebMock.allow_net_connect!
      else
        WebMock.disable_net_connect!
        servers_return_healthy
      end
    end
  end

  
  • Using an environment variable, INTEGRATION=true, you can turn off the WebMock routing and have the tests hit the real service.

Challenges

  1. Performing a Tear down, or cleaning, your third party test environment can be hard, if not impossible.
  2. Data from one test can then pollute other tests.

For something a little more elaborate, check out iOS Project Monitor’s Fake Parse Service and the WebMock Routing.

[16M05] Toggleable Mocks and Testing Strategies in a Service Oriented Architecture (en) from rubykaigi on Vimeo.

comments powered by Disqus