testing http calls with webmock and vcr
DESCRIPTION
Lightning talk for IPRUG, 5 March 2013TRANSCRIPT
Testing HTTP callsKerry Buckley
IPRUG lightning talk, 5 March 2013
Why?
Your app
Your tests
Webby stuff
WebmockTest::Unit Minitest RSpec Cucumber
Your app
Net::HTTP HTTPclient Patron EM-HTTP-request
Curb Typhoeus Excon
Webmock
Setupgroup :test do gem "webmock"end
require 'webmock/rspec'
require 'webmock/minitest'
require 'webmock/test_unit'
require 'webmock/cucumber'
Basic stub
stub_request :any, "www.example.com"
Net::HTTP.get "www.example.com", "/"
# => 200 OK, body = ""
Filtering requestsstub_request(:post, "www.example.com").
with(body: "abc", headers: {'Content-Length' => 3})
stub_http_request(:post, "www.example.com"). with(body: {data: {a: "1", b: "five"}})
stub_request(:post, "www.example.com"). with {|request| some_checks(request) }
Response
stub_request(:any, "www.example.com"). to_return(body: "abc", status: 200, headers: {'Content-Length' => 3} )
stub_request(:any, 'www.example.net'). to_return {|request| {body: request.body} }
Raising exceptionsstub_request(:any, 'www.example.net'). to_raise("some error")
stub_request(:any, 'www.example.net'). to_raise(Errno::ECONNRESET.new("some error"))
stub_request(:any, 'www.example.net'). to_raise(Errno::ETIMEDOUT)
stub_request(:any, 'www.example.net').to_timeout
Stubbing with Rack
class MyRackApp def self.call(env) [200, {}, ["Hello"]] endend
stub_request(:get, "www.example.com"). to_rack(MyRackApp)
Allow real requests
WebMock.allow_net_connect!
WebMock.disable_net_connect!( allow_localhost: true)
WebMock.disable_net_connect!( allow: "www.example.org:8080")
Expectationsrequire 'webmock/rspec'
WebMock.should_not have_requested(:get, "www.something.com")
WebMock.should have_requested(:get, "www.example.com"). with(body: "abc", headers: {'Content-Length' => 3}).twice
WebMock.should have_requested(:get, "www.example.com"). with(query: {"a" => ["b", "c"]})
Replaying curl
`curl -is www.example.com > /tmp/example.txt`raw_response_file = File.new("/tmp/example.txt")
stub_request(:get, "www.example.com"). to_return(raw_response_file)
stub_request(:get, "www.example.com"). to_return(raw_response_file.read)
VCR
Your app
Your tests
Webby stuff
Setupgroup :test do gem "vcr"end
VCR.configure do |c| c.cassette_library_dir = "vcr_cassettes" c.hook_into :webmockend
VCR.use_cassette("example-dot-com-index") do Net::HTTP.get "www.example.com", "/"end
Library support
Test::Unit Minitest RSpec Cucumber
VCR
Webmock Fakeweb Faraday Excon
Typhoeus
RSpecRSpec.configure do |c|
c.extend VCR::RSpec::Macrosend
describe "something" do use_vcr_cassette
it "does something" do ... endend
CucumberVCR.cucumber_tags do |t|
t.tag '@example-dot-com-index' t.tag '@example-dot-com-another-request'end
Feature: VCR stuff
@example-dot-com-index Scenario: Do something Given foo When bar Then baz
Cassettes---http_interactions:- request: method: get uri: http://example.com/ body: '' headers: {} response: status: code: 200 message: OK headers: Content-Type: - text/html;charset=utf-8 Content-Length: - '26' body: This is the response body http_version: '1.1' recorded_at: Tue, 01 Nov 2011 04:58:44 GMTrecorded_with: VCR 2.0.0
Request matchingVCR.configure do |c| c.default_cassette_options = { match_requests_on: [:method, :uri]}end
Also available:
•:host•:path•:query•:body•:headers
Ignoring requests
VCR.configure do |c| c.ignore_request do |request| URI(request.uri).port == 7777 end
c.ignore_hosts "foo.com", "bar.com"
c.ignore_localhost = trueend
SummaryUse Webmock (or Fakeweb)
• For fine-grained control
• If remote server isn’t available
Use VCR
• When record/replay is enough
• For an easy life