SlideShare a Scribd company logo
Effectively
Testing Services
Neal Kemp
$ whoami
Iowa native
Now: Californian
Software Developer
Independent Consultant
What I Do
Ruby / Rails
Javascript / Angular
HTML, CSS, etc
what,why&how
of testing services
NOT
Building testable services
NOT
Test-driven development
(necessarily)
	
  
… and because I don’t want @dhh to rage
what
What is a service?
Internal “SOA”
Any time you make an HTTP
request to an endpoint in
another repository
why
Why are services important?
Build faster
Makes scaling easier
Use them on virtually every application
Increasingly prevalent
Services are critical to
modern Rails development
Why is testing services important?
You (should) test everything else
Services compose crucial features
You may encounter problems…
Internal API
Sometimes null responses
Inconsistencies
Catastrophe
Okay? But what about external APIs?
Effectively Testing Services on Rails - Railsconf 2014
{"id": 24}	
{"code": "ANA"}
"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"	
}
No versioning!
Effectively Testing Services on Rails - Railsconf 2014
Snapchat Client
Haphazard documentation
What are the requests?
Bizarre obfuscation
github.com/nneal/snapcat
how
What is different about services?
External network requests
You don’t own the code
Effectively Testing Services on Rails - Railsconf 2014
On an airplane…
Failure is bad!
No network requests
Don’t interact with services from
test environment* **
* Includes “dummy” APIs
** Using pre-recorded responses
is okay
Assuming: Rails, rspec
Timetostub!
Built-in Stubbing
Typhoeus
Faraday
Excon
Simplify.
gem 'webmock'
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
Effectively Testing Services on Rails - Railsconf 2014
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
require 'facebook_wrapper'	
config/intializers/facebook_wrapper.rb
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
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
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
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
Even Better
No network requests
Fast!
No intermittent failure
Mock-Services
AWS
FB graph mock
OmniAuth
Etc…
gem 'fb_graph-mock'
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
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
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
Even Better
Already stubbed for you
Pre-recorded responses (sometimes)
Don’t need to know API endpoints
gem 'sham_rack'
gem 'sinatra'
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
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
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
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
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
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
Even Better
Dynamic
Expressive
Readable
gem 'vcr'
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
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
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
Even Better
Record API automatically
Replay responses without network
Verify responses
Additional Build Process
Runs outside normal test mode
Rechecks cassettes for diffs
Avoids versioning issues
gem 'puffing-billy'
Puffing-Billy
Built for in-browser requests
Allowed to record and reuse (like VCR)
Be brave, venture
out of ruby
I also like…
Chrome Dev Tools
Postman
HTTPie
Charles
Additional Reading
martinfowler.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
Bringing it all together
Testing services is crucial
If in doubt, stub it out
Determine the flexibility you want
Record responses to save time
Next Up
Eliminating Inconsistent Test Failures
with Austin Putman
Thank you!
me@nealke.mp
(I like emails)
@neal_kemp
(I tweet)

More Related Content

What's hot (18)

PDF
Flickr Open Api Mashup
Jinho Jung
 
PDF
2019-03 PHP without PHP Architecture @ Confoo
terry chay
 
PDF
Components are the Future of the Web: It’s Going To Be Okay
FITC
 
PPTX
สปริงเฟรมเวิร์ค4.1
ทวิร พานิชสมบัติ
 
PPTX
Poisoning Google images
lukash4
 
PDF
Web Scraping is BS
John D
 
ODP
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
Chris Toohey
 
PDF
MTC 2013 Berlin - Best Practices for Multi Devices
Hasan Hosgel
 
PDF
Technical SEO - Gone is Never Gone - Fixing Generational Cruft and Technical ...
Dawn Anderson MSc DigM
 
PPTX
Mood analyzer-virtual-dev-conf
Sherry List
 
PDF
Fetch me if you can - Handling API data in different JS frameworks
Marco Pagni
 
PPT
Advanced SEO for Web Developers
Nathan Buggia
 
PPT
Forum Presentation
Angus Pratt
 
KEY
Intro to developing for @twitterapi (updated)
Raffi Krikorian
 
PDF
Semantic Searchmonkey
Paul Tarjan
 
PDF
Intro to developing for @twitterapi
Raffi Krikorian
 
KEY
Elegant APIs
Andrew Timberlake
 
PDF
FoundConf 2018 Signals Speak - Alexis Sanders
Alexis Sanders
 
Flickr Open Api Mashup
Jinho Jung
 
2019-03 PHP without PHP Architecture @ Confoo
terry chay
 
Components are the Future of the Web: It’s Going To Be Okay
FITC
 
สปริงเฟรมเวิร์ค4.1
ทวิร พานิชสมบัติ
 
Poisoning Google images
lukash4
 
Web Scraping is BS
John D
 
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
Chris Toohey
 
MTC 2013 Berlin - Best Practices for Multi Devices
Hasan Hosgel
 
Technical SEO - Gone is Never Gone - Fixing Generational Cruft and Technical ...
Dawn Anderson MSc DigM
 
Mood analyzer-virtual-dev-conf
Sherry List
 
Fetch me if you can - Handling API data in different JS frameworks
Marco Pagni
 
Advanced SEO for Web Developers
Nathan Buggia
 
Forum Presentation
Angus Pratt
 
Intro to developing for @twitterapi (updated)
Raffi Krikorian
 
Semantic Searchmonkey
Paul Tarjan
 
Intro to developing for @twitterapi
Raffi Krikorian
 
Elegant APIs
Andrew Timberlake
 
FoundConf 2018 Signals Speak - Alexis Sanders
Alexis Sanders
 

Similar to Effectively Testing Services on Rails - Railsconf 2014 (20)

PDF
Effectively Testing Services - Burlington Ruby Conf
neal_kemp
 
PDF
RSpec 2 Best practices
Andrea Reginato
 
PDF
Testing Services Effectively
Alberto Leal
 
PDF
Programmers slang
bocribbz
 
PDF
2011-02-03 LA RubyConf Rails3 TDD Workshop
Wolfram Arnold
 
PDF
Tips and tricks for building api heavy ruby on rails applications
Tim Cull
 
PPT
Ruby on Rails testing with Rspec
Bunlong Van
 
PDF
How to Write Better Code with Mutation Testing
John Backus
 
KEY
Simple Web Apps With Sinatra
a_l
 
PDF
RSpec best practice - avoid using before and let
Bruce Li
 
PDF
Peepcode facebook-2-rails on facebook
sushilprajapati
 
PDF
Sinatra and JSONQuery Web Service
vvatikiotis
 
PDF
Testing RESTful Web Services
TechWell
 
PPTX
Women Who Code - RSpec JSON API Workshop
Eddie Lau
 
PDF
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
Marakana Inc.
 
PDF
RSpec 3: The new, the old, the good
mglrnm
 
PDF
Testing Merb
Yehuda Katz
 
ZIP
Rspec Tips
lionpeal
 
PDF
Controller specs
Alexander Miller
 
PDF
Testing RESTful Web Services
TechWell
 
Effectively Testing Services - Burlington Ruby Conf
neal_kemp
 
RSpec 2 Best practices
Andrea Reginato
 
Testing Services Effectively
Alberto Leal
 
Programmers slang
bocribbz
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
Wolfram Arnold
 
Tips and tricks for building api heavy ruby on rails applications
Tim Cull
 
Ruby on Rails testing with Rspec
Bunlong Van
 
How to Write Better Code with Mutation Testing
John Backus
 
Simple Web Apps With Sinatra
a_l
 
RSpec best practice - avoid using before and let
Bruce Li
 
Peepcode facebook-2-rails on facebook
sushilprajapati
 
Sinatra and JSONQuery Web Service
vvatikiotis
 
Testing RESTful Web Services
TechWell
 
Women Who Code - RSpec JSON API Workshop
Eddie Lau
 
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
Marakana Inc.
 
RSpec 3: The new, the old, the good
mglrnm
 
Testing Merb
Yehuda Katz
 
Rspec Tips
lionpeal
 
Controller specs
Alexander Miller
 
Testing RESTful Web Services
TechWell
 
Ad

Recently uploaded (20)

PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PPTX
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PDF
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
PPTX
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
PPTX
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
PPTX
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
PDF
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PDF
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
PDF
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
PPTX
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PPTX
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
Ad

Effectively Testing Services on Rails - Railsconf 2014

Editor's Notes

  • #11: Includes: things like Stripe, or an internal API, or an iPhone app calling into an API exposed by your rails app
  • #22: LA kings checkingchicagoblackhawks
  • #44: Can back with yaml
  • #50: Can back with yaml
  • #59: Can back with yaml
  • #64: Can back with yaml
  • #66: Re-writing web proxyAllowed to record and reuse (like VCR)
  • #67: Can back with yaml
  • #70: Ubiquitous PowerfulIn-browser (so easy!)
  • #71: Easily send requestsEasy-to-use GUI
  • #72: Postman without the GUICould run small scripts around it
  • #73: re-writing web proxyTest mobile as well as desktopGood for collecting a lot of responsesGood for testing things that aren’t specific page loads in ChromeGood when you don’t know what’s even being requested!