effectively testing services on rails - railsconf 2014
DESCRIPTION
Testing services with Ruby on Rails for Railsconf 2014. Test SOA or external services with ease.TRANSCRIPT
![Page 1: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/1.jpg)
Effectively
Testing
ServicesNeal Kemp
![Page 2: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/2.jpg)
$ whoami
Iowa native
Now: Californian
Software Developer
Independent Consultant
![Page 3: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/3.jpg)
What I Do
Ruby / Rails
Javascript / Angular
HTML, CSS, etc
![Page 4: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/4.jpg)
what, why & howof testing services
![Page 5: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/5.jpg)
NOT Building testable services
![Page 6: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/6.jpg)
NOT Test-driven development
(necessarily)
![Page 7: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/7.jpg)
… and because I don’t want @dhh to rage
![Page 8: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/8.jpg)
what
![Page 9: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/9.jpg)
What is a service?
Internal “SOA”
![Page 10: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/10.jpg)
Any time you make an HTTP
request to an endpoint in
another repository
![Page 11: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/11.jpg)
why
![Page 12: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/12.jpg)
Why are services important?
Build faster
Makes scaling easier
Use them on virtually every application
Increasingly prevalent
![Page 13: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/13.jpg)
Services are critical to
modern Rails
development
![Page 14: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/14.jpg)
Why is testing services
important?You (should) test everything else
Services compose crucial features
You may encounter problems…
![Page 15: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/15.jpg)
Internal API
Sometimes null responses
Inconsistencies
Catastrophe
![Page 16: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/16.jpg)
Okay? But what about external APIs?
![Page 17: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/17.jpg)
![Page 18: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/18.jpg)
{"id": 24}
{"code": "ANA"}
![Page 19: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/19.jpg)
"goals":[
{
"per":"1",
"ta":"CGY",
"et":"14:11",
"st":"Wrist Shot"
},
{
"per":"2",
"ta":"ANA",
"et":"11:12",
"st":"Backhand"
}
]
"goals": {
"per":"1",
"ta":"CGY",
"et":"14:11",
"st":"Wrist Shot"
}
![Page 20: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/20.jpg)
No versioning!
![Page 21: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/21.jpg)
![Page 22: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/22.jpg)
Snapchat Client
Haphazard documentation
What are the requests?
Bizarre obfuscation
github.com/nneal/snapcat
![Page 23: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/23.jpg)
how
![Page 24: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/24.jpg)
What is different about
services?External network requests
You don’t own the code
![Page 25: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/25.jpg)
![Page 26: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/26.jpg)
On an airplane…
Failure is bad!
No network requests
![Page 27: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/27.jpg)
Don’t interact with services from
test environment* **
![Page 28: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/28.jpg)
* Includes “dummy” APIs
![Page 29: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/29.jpg)
** Using pre-recorded
responses is okay
![Page 30: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/30.jpg)
Assuming:
Rails, rspec
![Page 31: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/31.jpg)
Time to stub!
![Page 32: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/32.jpg)
Built-in Stubbing
Typhoeus
Faraday
Excon
![Page 33: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/33.jpg)
Simplify.
![Page 34: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/34.jpg)
gem 'webmock'
![Page 35: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/35.jpg)
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/autorun'
require 'rspec/rails’
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.order = 'random’
end
WebMock.disable_net_connect!
spec/spec_helper.rb
![Page 36: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/36.jpg)
![Page 37: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/37.jpg)
module FacebookWrapper
def self.user_id(username)
user_data(username)['id']
end
def self.user_data(username)
JSON.parse(
open("https://graph.facebook.com/#{username}").read
)
end
end
lib/facebook_wrapper.rb
![Page 38: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/38.jpg)
require 'facebook_wrapper'
config/intializers/facebook_wrapper.rb
![Page 39: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/39.jpg)
require 'spec_helper'
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
stub_request(:get, 'https://graph.facebook.com/arjun').
to_return(
status: 200,
headers: {},
body: '{
"id": "7901103","first_name": "Arjun",
"locale": "en_US","username": "Arjun"
}'
)
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 40: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/40.jpg)
require 'spec_helper'
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
stub_request(:get, 'https://graph.facebook.com/arjun').
to_return(
status: 200,
headers: {},
body: '{
"id": "7901103","first_name": "Arjun",
"locale": "en_US","username": "Arjun"
}'
)
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 41: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/41.jpg)
require 'spec_helper'
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
stub_request(:get, 'https://graph.facebook.com/arjun').
to_return(
status: 200,
headers: {},
body: '{
"id": "7901103","first_name": "Arjun",
"locale": "en_US","username": "Arjun"
}'
)
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 42: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/42.jpg)
require 'spec_helper'
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
stub_request(:get, 'https://graph.facebook.com/arjun').
to_return(
status: 200,
headers: {},
body: '{
"id": "7901103","first_name": "Arjun",
"locale": "en_US","username": "Arjun"
}'
)
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 43: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/43.jpg)
Even Better
No network requests
Fast!
No intermittent failure
![Page 44: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/44.jpg)
Mock-Services
AWS
FB graph mock
OmniAuth
Etc…
![Page 45: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/45.jpg)
gem 'fb_graph-mock'
![Page 46: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/46.jpg)
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/autorun'
require 'rspec/rails’
require 'fb_graph/mock'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.order = 'random'
config.include FbGraph::Mock
end
WebMock.disable_net_connect!
spec/spec_helper.rb
![Page 47: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/47.jpg)
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
mock_graph :get, 'arjun', 'users/arjun_public' do
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 48: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/48.jpg)
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
mock_graph :get, 'arjun', 'users/arjun_public' do
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 49: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/49.jpg)
Even Better
Already stubbed for you
Pre-recorded responses (sometimes)
Don’t need to know API endpoints
![Page 50: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/50.jpg)
gem 'sham_rack'
![Page 51: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/51.jpg)
gem 'sinatra'
![Page 52: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/52.jpg)
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/autorun'
require 'rspec/rails’
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.order = 'random’
end
WebMock.disable_net_connect!
spec/spec_helper.rb
![Page 53: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/53.jpg)
ShamRack.at('graph.facebook.com', 443).sinatra do
get '/:username' do
%Q|{
"id": "7901103",
"name": "Arjun Banker",
"first_name": "Arjun",
"last_name": "Banker",
"link": "http://www.facebook.com/#{params[:username]}",
"location": {
"id": 114952118516947,
"name": "San Francisco, California"
},
"gender": "male"
}|
end
end
spec/support/fake_facebook.rb
![Page 54: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/54.jpg)
ShamRack.at('graph.facebook.com', 443).sinatra do
get '/:username' do
%Q|{
"id": "7901103",
"name": "Arjun Banker",
"first_name": "Arjun",
"last_name": "Banker",
"link": "http://www.facebook.com/#{params[:username]}",
"location": {
"id": 114952118516947,
"name": "San Francisco, California"
},
"gender": "male"
}|
end
end
spec/support/fake_facebook.rb
![Page 55: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/55.jpg)
ShamRack.at('graph.facebook.com', 443).sinatra do
get '/:username' do
%Q|{
"id": "7901103",
"name": "Arjun Banker",
"first_name": "Arjun",
"last_name": "Banker",
"link": "http://www.facebook.com/#{params[:username]}",
"location": {
"id": 114952118516947,
"name": "San Francisco, California"
},
"gender": "male"
}|
end
end
spec/support/fake_facebook.rb
![Page 56: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/56.jpg)
ShamRack.at('graph.facebook.com', 443).sinatra do
get '/:username' do
%Q|{
"id": "7901103",
"name": "Arjun Banker",
"first_name": "Arjun",
"last_name": "Banker",
"link": "http://www.facebook.com/#{params[:username]}",
"location": {
"id": 114952118516947,
"name": "San Francisco, California"
},
"gender": "male"
}|
end
end
spec/support/fake_facebook.rb
![Page 57: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/57.jpg)
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103’
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 58: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/58.jpg)
Even Better
Dynamic
Expressive
Readable
![Page 59: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/59.jpg)
gem 'vcr'
![Page 60: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/60.jpg)
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/autorun'
require 'rspec/rails’
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.order = 'random’
end
WebMock.disable_net_connect!
VCR.configure do |c|
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
c.hook_into :webmock
end spec/spec_helper.rb
![Page 61: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/61.jpg)
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
VCR.use_cassette('fb_user_arjun') do
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 62: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/62.jpg)
describe FacebookWrapper, '.user_link' do
it 'retrieves user link' do
VCR.use_cassette('fb_user_arjun') do
user_id = FacebookWrapper.user_id('arjun')
expect(user_id).to eq '7901103'
end
end
end
spec/lib/facebook_wrapper_spec.rb
![Page 63: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/63.jpg)
Even Better
Record API automatically
Replay responses without network
Verify responses
![Page 64: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/64.jpg)
Additional Build Process
Runs outside normal test mode
Rechecks cassettes for diffs
Avoids versioning issues
![Page 65: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/65.jpg)
gem 'puffing-billy'
![Page 66: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/66.jpg)
Puffing-Billy
Built for in-browser requests
Allowed to record and reuse (like VCR)
![Page 67: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/67.jpg)
Be brave, venture out
of ruby
![Page 68: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/68.jpg)
I also like…
![Page 69: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/69.jpg)
Chrome Dev Tools
![Page 70: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/70.jpg)
Postman
![Page 71: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/71.jpg)
HTTPie
![Page 72: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/72.jpg)
Charles
![Page 73: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/73.jpg)
Additional Readingmartinfowler.com/bliki/IntegrationContractTest.html
robots.thoughtbot.com/how-to-stub-external-services-in-tests
joblivious.wordpress.com/2009/02/20/handling-intermittence-how-to-
survive-test-driven-development
railscasts.com/episodes/291-testing-with-vcr
![Page 74: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/74.jpg)
Bringing it all together
Testing services is crucial
If in doubt, stub it out
Determine the flexibility you want
Record responses to save time
![Page 75: Effectively Testing Services on Rails - Railsconf 2014](https://reader033.vdocuments.net/reader033/viewer/2022060107/5549d1bfb4c9057c6d8b4e37/html5/thumbnails/75.jpg)
Next Up
Eliminating Inconsistent Test Failures
with Austin Putman