Marnen E. Laibow-Koser
September 2010, revised June 2012
class Twitter include HTTParty def self.user_info(username, format = :json) get "http://api.twitter.com/1/users/show/#{username}.#{format}" end end
Call the external service and make sure we’re processing the result
describe Twitter do describe "user_info" do it "should get extended user information" do Twitter.user_info('marnen')['name'].should == "Marnen Laibow-Koser" end end end
WRONG!
describe Twitter do describe "user_info" do it "should get extended user information" do Twitter.user_info('marnen')['name'].should == "Marnen Laibow-Koser" end end end
http://github.com/bblimke/webmock
gem install webmock
spec/spec_helper
require 'webmock/rspec' Spec::Runner.configure do |config| config.include WebMock end
features/support/env.rb
require 'webmock/rspec' module WebMockWorld include WebMock include WebMock::Matchers end World(WebMockWorld)
(Works with Test::Unit too.)
stub_request(:get, "www.example.com").to_return(:body => "My canned response")
stub_request(:post, "www.example.com").with(:query => {'name' => 'marnen'})
stub_request(:any, /^www\.example\.(com|net|org)/)
curl -is http://api.twitter.com/1/users/show/marnen.json > canned_response.json
canned_response.json
HTTP/1.1 200 OK {"screen_name":"marnen", "name":"Marnen Laibow-Koser", ...}
describe Twitter do describe "user_info" do it "should get extended user information" do canned_response = File.new 'canned_response.json' stub_request(:get, "api.twitter.com/1/users/show/marnen.json").to_return(canned_response) Twitter.user_info('marnen')['name'].should == "Marnen Laibow-Koser" end end end
It’s tedious to use curl to get all those canned responses. Fortunately, we don’t have to.
https://github.com/myronmarston/vcr
gem install vcr
Put this in a Cucumber support file (also works with RSpec and Test::Unit)
require 'vcr' VCR.configure do |c| c.cassette_library_dir = 'fixtures/vcr_cassettes' c.hook_into :webmock end VCR.cucumber_tags do |t| t.tag '@vcr', :use_scenario_name => true end
Tag your scenarios with @vcr
or call VCR directly in your steps
And then, just run your tests as normal—no more messing with curl!
:once
:new_episodes
:none
:all
VCR.use_cassette('dynamic', :erb => { :arg1 => 7, :arg2 => 'baz' })
No external calls means no external dependencies
No network overhead!
WebMock raises an exception if it doesn’t recognize an HTTP request
forbidden.json
HTTP/1.1 403 Forbidden
spec/models/twitter_spec.rb
describe Twitter do it "should gracefully handle error conditions" do stub_request(:any, /^api\.twitter\.com/).to_return(File.new 'forbidden.json') lambda { Twitter.user_info('forbidden') }.should_not raise_error end end
http://github.com/bblimke/webmock
https://github.com/myronmarston/vcr