SlideShare a Scribd company logo
1 of 43
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


                                 HTTP 200 - OK
                      Content-Type: application/json
                               Here is your location:
                     {"latitude"=>"51.52","longitude":-0.12"}




                                                           new bamboo
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
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
new bamboo
new bamboo
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
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
new bamboo
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
new bamboo
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
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 based on request
  method, uri, body and headers
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
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
WebMock


          new bamboo
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
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
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
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
new bamboo
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
new bamboo
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
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
Cucumber
features/common/env.rb

require 'webmock'
include WebMock

Before do
  WebMock.disable_net_connect!
  WebMock.reset_webmock
end




                                 new bamboo
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
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
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
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?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
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
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
Dynamic Responses
stub_request(:any, 'www.example.net').
  to_return(:body => lambda { |request| request.body })

RestClient.post('www.example.net', 'abc')   # ===> "abcn"




                                                  new bamboo
Supported Libraries

Net::HTTP    HTTPClient




                          new bamboo
Supported Libraries

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



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




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




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



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



                                         new bamboo

More Related Content

What's hot

Beyond Page Level Metrics
Beyond Page Level MetricsBeyond Page Level Metrics
Beyond Page Level MetricsPhilip Tellis
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go ConcurrencyCloudflare
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparisonHiroshi Nakamura
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHPKing Foo
 
Http capturing
Http capturingHttp capturing
Http capturingEric Ahn
 
Puppet Performance Profiling
Puppet Performance ProfilingPuppet Performance Profiling
Puppet Performance Profilingripienaar
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisFastly
 
Flask With Server-Sent Event
Flask With Server-Sent EventFlask With Server-Sent Event
Flask With Server-Sent EventTencent
 
Testing your infrastructure with litmus
Testing your infrastructure with litmusTesting your infrastructure with litmus
Testing your infrastructure with litmusBram Vogelaar
 
HTTPBuilder NG: Back From The Dead
HTTPBuilder NG: Back From The DeadHTTPBuilder NG: Back From The Dead
HTTPBuilder NG: Back From The Deadnoamt
 
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!MongoDB World 2019: Becoming an Ops Manager Backup Superhero!
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!MongoDB
 
Observability with Consul Connect
Observability with Consul ConnectObservability with Consul Connect
Observability with Consul ConnectBram Vogelaar
 
Autoscaling with hashi_corp_nomad
Autoscaling with hashi_corp_nomadAutoscaling with hashi_corp_nomad
Autoscaling with hashi_corp_nomadBram Vogelaar
 
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...Willian Molinari
 
How we use and deploy Varnish at Opera
How we use and deploy Varnish at OperaHow we use and deploy Varnish at Opera
How we use and deploy Varnish at OperaCosimo Streppone
 
VUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareVUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareCosimo Streppone
 
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Using Node.js to  Build Great  Streaming Services - HTML5 Dev ConfUsing Node.js to  Build Great  Streaming Services - HTML5 Dev Conf
Using Node.js to Build Great Streaming Services - HTML5 Dev ConfTom Croucher
 
Integrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteIntegrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteBram Vogelaar
 

What's hot (20)

Beyond Page Level Metrics
Beyond Page Level MetricsBeyond Page Level Metrics
Beyond Page Level Metrics
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go Concurrency
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
 
Http capturing
Http capturingHttp capturing
Http capturing
 
Puppet Performance Profiling
Puppet Performance ProfilingPuppet Performance Profiling
Puppet Performance Profiling
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
Flask With Server-Sent Event
Flask With Server-Sent EventFlask With Server-Sent Event
Flask With Server-Sent Event
 
Testing your infrastructure with litmus
Testing your infrastructure with litmusTesting your infrastructure with litmus
Testing your infrastructure with litmus
 
HTTPBuilder NG: Back From The Dead
HTTPBuilder NG: Back From The DeadHTTPBuilder NG: Back From The Dead
HTTPBuilder NG: Back From The Dead
 
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!MongoDB World 2019: Becoming an Ops Manager Backup Superhero!
MongoDB World 2019: Becoming an Ops Manager Backup Superhero!
 
Observability with Consul Connect
Observability with Consul ConnectObservability with Consul Connect
Observability with Consul Connect
 
Autoscaling with hashi_corp_nomad
Autoscaling with hashi_corp_nomadAutoscaling with hashi_corp_nomad
Autoscaling with hashi_corp_nomad
 
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...
How we used ruby to build locaweb's cloud (http://presentations.pothix.com/ru...
 
How we use and deploy Varnish at Opera
How we use and deploy Varnish at OperaHow we use and deploy Varnish at Opera
How we use and deploy Varnish at Opera
 
vBACD - Introduction to Opscode Chef - 2/29
vBACD - Introduction to Opscode Chef - 2/29vBACD - Introduction to Opscode Chef - 2/29
vBACD - Introduction to Opscode Chef - 2/29
 
VUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareVUG5: Varnish at Opera Software
VUG5: Varnish at Opera Software
 
Nodejs meetup-12-2-2015
Nodejs meetup-12-2-2015Nodejs meetup-12-2-2015
Nodejs meetup-12-2-2015
 
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Using Node.js to  Build Great  Streaming Services - HTML5 Dev ConfUsing Node.js to  Build Great  Streaming Services - HTML5 Dev Conf
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
 
Integrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteIntegrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suite
 

Viewers also liked (20)

Green2
Green2Green2
Green2
 
Week4 a2
Week4 a2Week4 a2
Week4 a2
 
S P W13
S P W13S P W13
S P W13
 
B
BB
B
 
Energy Efficiency In The Office
Energy Efficiency In The OfficeEnergy Efficiency In The Office
Energy Efficiency In The Office
 
Week10 b
Week10 bWeek10 b
Week10 b
 
Sp W13
Sp W13Sp W13
Sp W13
 
Espolon Oeste
Espolon OesteEspolon Oeste
Espolon Oeste
 
Espolon Oeste
Espolon OesteEspolon Oeste
Espolon Oeste
 
Soil
SoilSoil
Soil
 
C w6
C w6C w6
C w6
 
C w3
C w3C w3
C w3
 
Week4 a2
Week4 a2Week4 a2
Week4 a2
 
B w6
B w6B w6
B w6
 
Week9 b
Week9 bWeek9 b
Week9 b
 
C w3
C w3C w3
C w3
 
Sp W12
Sp W12Sp W12
Sp W12
 
Presentation w6
Presentation w6Presentation w6
Presentation w6
 
W11 b
W11 bW11 b
W11 b
 
Sp W10
Sp W10Sp W10
Sp W10
 

Similar to TDD of HTTP Clients With WebMock

Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...
Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...
Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...confluent
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineAndy McKay
 
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...DynamicInfraDays
 
Unit Testing Express Middleware
Unit Testing Express MiddlewareUnit Testing Express Middleware
Unit Testing Express MiddlewareMorris Singer
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleVladimir Kostyukov
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourPeter Friese
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftChris Bailey
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCLFastly
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express Jeetendra singh
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLAll Things Open
 

Similar to TDD of HTTP Clients With WebMock (20)

Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...
Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...
Using Location Data to Showcase Keys, Windows, and Joins in Kafka Streams DSL...
 
Intro to Sail.js
Intro to Sail.jsIntro to Sail.js
Intro to Sail.js
 
huhu
huhuhuhu
huhu
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
 
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
 
Unit Testing Express Middleware
Unit Testing Express MiddlewareUnit Testing Express Middleware
Unit Testing Express Middleware
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with Finagle
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) Swift
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
 
Os Pruett
Os PruettOs Pruett
Os Pruett
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQL
 

Recently uploaded

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 

Recently uploaded (20)

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 

TDD of HTTP Clients With WebMock

  • 1. TDD of HTTP Clients with WebMock Bartosz Blimke @bartoszblimke new bamboo
  • 2. Test TDD RED RED Code new bamboo
  • 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. 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. 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
  • 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. 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
  • 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
  • 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. I wanted a tool for stubbing HTTP requests that...
  • 15. I wanted a tool for stubbing HTTP requests that... • doesn’t depend on usage of a specific API
  • 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. 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. 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. WebMock new bamboo
  • 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. 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. 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. 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
  • 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
  • 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. 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. Cucumber features/common/env.rb require 'webmock' include WebMock Before do WebMock.disable_net_connect! WebMock.reset_webmock end new bamboo
  • 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. 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. 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. Smart URI Matching www.example.net/my path?x=my params new bamboo
  • 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. 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. 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. 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. Supported Libraries Net::HTTP HTTPClient new bamboo
  • 39. Supported Libraries Net::HTTP HTTPClient HTTParty RESTClient RightScale::HttpConnection open-uri new bamboo

Editor's Notes

  1. 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 ....
  2. is test driven development. I&amp;#x2019;m doing TDD for about 3 or 4 years now.
  3. none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  4. none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  5. none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features
  6. none of the tools I found offered these features, and non of the tools I found were easily extandable to implement these features