Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
TDD of HTTP Clients
  with WebMock
     Bartosz Blimke
     @bartoszblimke




                      new bamboo
Test



TDD
RED
RED


       Code


              new bamboo
Hello http://my.geoservice.org
    Give me location for zip code WC1H 9EF
GET http://my.geoservice.org/?zip=WC1H 9EF


   ...
describe GeoCoordinatesFinder do

  it "should make http request to geocoding service" do



  end

  it "should report co...
describe GeoCoordinatesFinder do

  it "should make http request to geocoding service" do

        ???
  end

  it "should...
new bamboo
new bamboo
class GeoCoordinatesFinder

  def get_coordinates_by_zip_code(zip)
    res = Net::HTTP.start("my.geoservice.org", 80) { |h...
describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = GeoCoordinatesFinder.new
    @mock_http = m...
new bamboo
class GeoCoordinatesFinder

  def get_coordinates_by_zip_code(zip)
    url = "http://my.geoservice.org?zip=#{URI.encode(zi...
new bamboo
describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = GeoCoordinatesFinder.new
    RestClient.stu...
I wanted a tool for stubbing
   HTTP requests that...
I wanted a tool for stubbing
    HTTP requests that...
• doesn’t depend on usage of a specific API
I wanted a tool for stubbing
    HTTP requests that...
• doesn’t depend on usage of a specific API
• supports stubbing base...
I wanted a tool for stubbing
    HTTP requests that...
• doesn’t depend on usage of a specific API
• supports stubbing base...
I wanted a tool for stubbing
    HTTP requests that...
• doesn’t depend on usage of a specific API
• supports stubbing base...
WebMock


          new bamboo
require 'webmock/rspec'
include WebMock

describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = Ge...
require 'webmock/rspec'
include WebMock

describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = Ge...
require 'webmock/rspec'
include WebMock

describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = Ge...
require 'webmock/rspec'
include WebMock

describe GeoCoordinatesFinder do

  before(:each) do
    @coordinates_finder = Ge...
new bamboo
class GeoCoordinatesFinder

  def get_coordinates_by_zip_code(zip)
    uri = "http://my_geoservice.org?zip=#{URI.encode(zi...
new bamboo
Test::Unit
require 'webmock/test_unit'
include WebMock

class TestGeoCoordinatesFinder < Test::Unit::TestCase

  def setup...
Test::Unit
require 'webmock/test_unit'
include WebMock

class TestGeoCoordinatesFinder < Test::Unit::TestCase

  def setup...
Cucumber
features/common/env.rb

require 'webmock'
include WebMock

Before do
  WebMock.disable_net_connect!
  WebMock.res...
Cucumber
features/finding_geo_coordinates.feature
Feature: Finding the way to an awesome conference
  In order to find the...
Cucumber
  features/step_definitions/geocoding_service_steps.rb

Given /^geoservice reports (.+), (.+) as coordinates for ...
Matching Requests
              on Body and Headers
stub_request(:post, "www.example.net").
  with(:body => "abc", :header...
Smart URI Matching

www.example.net/my path?x=my params




                                      new bamboo
Smart URI Matching

www.example.net/my path?x=my params
www.example.net/my%20path?x=my%20params
www.example.net:80/my path...
Matching URIs with Regexp
stub_request(:post, /example/).
  with(:body => "abc", :headers => { :content_type => 'text/plai...
Basic Authentication
stub_request(:any, 'user:pass@www.example.net').
  to_return(:body => 'abc')

RestClient::Resource.ne...
Dynamic Responses
stub_request(:any, 'www.example.net').
  to_return(:body => lambda { |request| request.body })

RestClie...
Supported Libraries

Net::HTTP    HTTPClient




                          new bamboo
Supported Libraries

Net::HTTP         HTTPClient
HTTParty
RESTClient
RightScale::HttpConnection
open-uri



             ...
http://github.com/bblimke/webmock




                                    new bamboo
http://github.com/bblimke/webmock
http://groups.google.com/group/webmock-users




                                       ...
http://github.com/bblimke/webmock
http://groups.google.com/group/webmock-users
bartosz@new-bamboo.co.uk
@bartoszblimke



...
Questions?
http://github.com/bblimke/webmock
http://groups.google.com/group/webmock-users
bartosz@new-bamboo.co.uk
@bartos...
Upcoming SlideShare
Loading in …5
×

TDD of HTTP Clients With WebMock

9,657 views

Published on

My presentation about Test Driven Development of HTTP clients using WebMock, presented at RubyManor 2.
WebMock is a library for stubbing and setting expectations on HTTP requests in Ruby.

Published in: Technology, Business

TDD of HTTP Clients With WebMock

  1. 1. TDD of HTTP Clients with WebMock Bartosz Blimke @bartoszblimke new bamboo
  2. 2. Test TDD RED RED Code new bamboo
  3. 3. Hello http://my.geoservice.org Give me location for zip code WC1H 9EF GET http://my.geoservice.org/?zip=WC1H 9EF HTTP 200 - OK Content-Type: application/json Here is your location: {"latitude"=>"51.52","longitude":-0.12"} new bamboo
  4. 4. describe GeoCoordinatesFinder do it "should make http request to geocoding service" do end it "should report coordinates provided by geocoding service" do end end new bamboo
  5. 5. describe GeoCoordinatesFinder do it "should make http request to geocoding service" do ??? end it "should report coordinates provided by geocoding service" do ??? end end new bamboo
  6. 6. new bamboo
  7. 7. new bamboo
  8. 8. class GeoCoordinatesFinder def get_coordinates_by_zip_code(zip) res = Net::HTTP.start("my.geoservice.org", 80) { |http| http.get("/?zip=#{URI.encode(zip)}") } result = JSON.parse(res) [result['latitude'], result['longitude']] end end new bamboo
  9. 9. describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new @mock_http = mock("http") @res = mock(Net::HTTPOK, :body => "{"latitude":"5.5","longitude":"6.6"}") Net::HTTP.stub!(:start).with("my.geoservice.org", 80).and_yield @mock_http @mock_http.stub!(:get).with("/?zip=WC1H%209EF").and_return(@res) end it "should make http request to geocoding service" do Net::HTTP.should_receive(:start).and_yield @mock_http @mock_http.should_receive(:get).with("/?zip=WC1H%209EF") @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF").should == ["5.5", "6.6"] end end new bamboo
  10. 10. new bamboo
  11. 11. class GeoCoordinatesFinder def get_coordinates_by_zip_code(zip) url = "http://my.geoservice.org?zip=#{URI.encode(zip)}" response = RestClient.get(url) result = JSON.parse(response) [result['latitude'], result['longitude']] end end new bamboo
  12. 12. new bamboo
  13. 13. describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new RestClient.stub!(:get).with("http://my.geoservice.org?zip=WC1H%209EF"). and_return("{"latitude":"5.5","longitude":"6.6"}") end it "should make http request to yahoo geocoding service" do RestClient.should_receive(:get).with("http://my.geoservice.org?zip=WC1H%209EF") @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF").should == ["5.5", "6.6"] end end new bamboo
  14. 14. I wanted a tool for stubbing HTTP requests that...
  15. 15. I wanted a tool for stubbing HTTP requests that... • doesn’t depend on usage of a specific API
  16. 16. I wanted a tool for stubbing HTTP requests that... • doesn’t depend on usage of a specific API • supports stubbing based on request method, uri, body and headers
  17. 17. I wanted a tool for stubbing HTTP requests that... • doesn’t depend on usage of a specific API • supports stubbing based on request method, uri, body and headers • verifies expectations of requests
  18. 18. I wanted a tool for stubbing HTTP requests that... • doesn’t depend on usage of a specific API • supports stubbing based on request method, uri, body and headers • verifies expectations of requests • supports different HTTP libraries
  19. 19. WebMock new bamboo
  20. 20. require 'webmock/rspec' include WebMock describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end it "should make http request to geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") WebMock.should have_requested(:get, "http://my.geoservice.org?zip=WC1H 9EF") end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"). should == ["5.5", "6.6"] end end new bamboo
  21. 21. require 'webmock/rspec' include WebMock describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end it "should make http request to geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") WebMock.should have_requested(:get, "http://my.geoservice.org?zip=WC1H 9EF") end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"). should == ["5.5", "6.6"] end end new bamboo
  22. 22. require 'webmock/rspec' include WebMock describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end it "should make http request to geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") WebMock.should have_requested(:get, "http://my.geoservice.org?zip=WC1H 9EF") end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"). should == ["5.5", "6.6"] end end new bamboo
  23. 23. require 'webmock/rspec' include WebMock describe GeoCoordinatesFinder do before(:each) do @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end it "should make http request to geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") request(:get, "http://my.geoservice.org?zip=WC1H 9EF").should have_been_made end it "should report coordinates provided by geocoding service" do @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"). should == ["5.5", "6.6"] end end new bamboo
  24. 24. new bamboo
  25. 25. class GeoCoordinatesFinder def get_coordinates_by_zip_code(zip) uri = "http://my_geoservice.org?zip=#{URI.encode(zip)}" result = JSON.parse(HTTPClient.new.get(uri).content) [result['latitude'], result['longitude']] end end new bamboo
  26. 26. new bamboo
  27. 27. Test::Unit require 'webmock/test_unit' include WebMock class TestGeoCoordinatesFinder < Test::Unit::TestCase def setup @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end def test_making_request_to_geocoding_service @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") assert_requested :get, "http://my.geoservice.org?zip=WC1H 9EF" end def test_reporting_coordinates_provided_by_geocoding_service assert_equal @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"), ["5.5", "6.6"] end end new bamboo
  28. 28. Test::Unit require 'webmock/test_unit' include WebMock class TestGeoCoordinatesFinder < Test::Unit::TestCase def setup @coordinates_finder = GeoCoordinatesFinder.new stub_request(:get, "http://my.geoservice.org?zip=WC1H 9EF"). to_return(:body => "{"latitude":"5.5","longitude":"6.6"}") end def test_making_request_to_geocoding_service @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF") assert_requested :get, "http://my.geoservice.org?zip=WC1H 9EF" end def test_reporting_coordinates_provided_by_geocoding_service assert_equal @coordinates_finder.get_coordinates_by_zip_code("WC1H 9EF"), ["5.5", "6.6"] end end new bamboo
  29. 29. Cucumber features/common/env.rb require 'webmock' include WebMock Before do WebMock.disable_net_connect! WebMock.reset_webmock end new bamboo
  30. 30. Cucumber features/finding_geo_coordinates.feature Feature: Finding the way to an awesome conference In order to find the best way to Ruby Manor As a ruby geek I want to see how to get there on a map Scenario: User finds zip code coordinates on a map Given geoservice reports coordinates "51.52, -0.12" for zip code "WC1H 9EF" When I type "WC1H 9EF" into zip code field And I press "Show on map" Then I should see map centered at latitude "51.52" and longitude "-0.12" new bamboo
  31. 31. Cucumber features/step_definitions/geocoding_service_steps.rb Given /^geoservice reports (.+), (.+) as coordinates for zip code (.+)$/ do |lat, long, zip_code| stub_request(:get, "http://my.geoservice.org?zip=#{zip_code}"). to_return( :body => "{"latitude":"#{lat}","longitude":"#{long}"}" ) end new bamboo
  32. 32. Matching Requests on Body and Headers stub_request(:post, "www.example.net"). with(:body => "abc", :headers => { :content_type => 'text/plain' }) RestClient.post "www.example.net", "abc", :content_type => 'text/plain' WebMock.should have_requested(:post, "www.example.net"). with(:body => "abc", :headers => { 'Content-Type' => 'text/plain' }) new bamboo
  33. 33. Smart URI Matching www.example.net/my path?x=my params new bamboo
  34. 34. Smart URI Matching www.example.net/my path?x=my params www.example.net/my%20path?x=my%20params www.example.net:80/my path?x=my params www.example.net:80/my%20path?x=my%20params http://www.example.net/my path?x=my params http://www.example.net/my%20path?x=my%20params http://www.example.net:80/my path?x=my params http://www.example.net:80/my%20path?x=my%20params new bamboo
  35. 35. Matching URIs with Regexp stub_request(:post, /example/). with(:body => "abc", :headers => { :content_type => 'text/plain' }) RestClient.post "www.example.net", "abc", :content_type => 'text/plain' WebMock.should have_requested(:post, /example/). with(:body => "abc", :headers => { 'Content-Type' => 'text/plain' }) new bamboo
  36. 36. Basic Authentication stub_request(:any, 'user:pass@www.example.net'). to_return(:body => 'abc') RestClient::Resource.new( 'www.example.net', :user => 'user', :password => 'pass' ).post('abc') # ===> "abcn" WebMock.should have_requested(:post, 'user:pass@www.example.net') new bamboo
  37. 37. Dynamic Responses stub_request(:any, 'www.example.net'). to_return(:body => lambda { |request| request.body }) RestClient.post('www.example.net', 'abc') # ===> "abcn" new bamboo
  38. 38. Supported Libraries Net::HTTP HTTPClient new bamboo
  39. 39. Supported Libraries Net::HTTP HTTPClient HTTParty RESTClient RightScale::HttpConnection open-uri new bamboo
  40. 40. http://github.com/bblimke/webmock new bamboo
  41. 41. http://github.com/bblimke/webmock http://groups.google.com/group/webmock-users new bamboo
  42. 42. http://github.com/bblimke/webmock http://groups.google.com/group/webmock-users bartosz@new-bamboo.co.uk @bartoszblimke new bamboo
  43. 43. Questions? http://github.com/bblimke/webmock http://groups.google.com/group/webmock-users bartosz@new-bamboo.co.uk @bartoszblimke new bamboo

×