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

8,267

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
2 Comments
5 Likes
Statistics
Notes
No Downloads
Views
Total Views
8,267
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
60
Comments
2
Likes
5
Embeds 0
No embeds

No notes for slide
  • Hi. I&amp;#x2019;m Bartosz Blimke. I&amp;#x2019;m work for New Bamboo, a development shop. We are working in a rigorous agile environment and we also offer agile coaching.
    I&amp;#x2019;ve been working in Extreme Programming environments for the last 5 years, on small projects as well as on very big corporate projects.

    One of the code XP practices is ....
  • is test driven development. I&amp;#x2019;m doing TDD for about 3 or 4 years now.
  • none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  • none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  • none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  • none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  • 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
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×