Skip to content
Olia Kremmyda edited this page Mar 24, 2018 · 1 revision

Stubbing request based on uri only and with the default response

stub_request(:any, "www.example.com")

Net::HTTP.get("www.example.com", "/")    # ===> Success

Stubbing requests based on method, uri, body and headers

stub_request(:post, "www.example.com").
  with(body: "abc", headers: { 'Content-Length' => 3 })

uri = URI.parse("http://www.example.com/")
req = Net::HTTP::Post.new(uri.path)
req['Content-Length'] = 3

res = Net::HTTP.start(uri.host, uri.port) do |http|
  http.request(req, "abc")
end    # ===> Success

Matching request body and headers against regular expressions

stub_request(:post, "www.example.com").
  with(body: /world$/, headers: {"Content-Type" => /image\/.+/}).
  to_return(body: "abc")

uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Content-Type'] = 'image/png'

res = Net::HTTP.start(uri.host, uri.port) do |http|
  http.request(req, 'hello world')
end    # ===> Success

Matching request body against a hash. Body can be URL-Encoded, JSON or XML.

stub_request(:post, "www.example.com").
  with(body: {data: {a: '1', b: 'five'}})

RestClient.post('www.example.com', "data[a]=1&data[b]=five",
  content_type: 'application/x-www-form-urlencoded')    # ===> Success

RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
  content_type: 'application/json')    # ===> Success

RestClient.post('www.example.com', '<data a="1" b="five" />',
  content_type: 'application/xml')    # ===> Success

Matching request body against partial hash.

stub_request(:post, "www.example.com").
  with(body: hash_including({data: {a: '1', b: 'five'}}))

RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1",
:content_type => 'application/x-www-form-urlencoded')    # ===> Success

Matching custom request headers

stub_request(:any, "www.example.com").
  with(headers:{ 'Header-Name' => 'Header-Value' })

uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Header-Name'] = 'Header-Value'

res = Net::HTTP.start(uri.host, uri.port) do |http|
  http.request(req, 'abc')
end    # ===> Success

Matching multiple headers with the same name

stub_request(:get, 'www.example.com').
  with(headers: {'Accept' => ['image/jpeg', 'image/png'] })

req = Net::HTTP::Get.new("/")
req['Accept'] = ['image/png']
req.add_field('Accept', 'image/jpeg')
Net::HTTP.start("www.example.com") {|http| http.request(req) }    # ===> Success

Matching requests against provided block

stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
RestClient.post('www.example.com', 'abc')    # ===> Success

Request with basic authentication header

stub_request(:get, "www.example.com").with(basic_auth: ['user', 'pass'])
# or
# stub_request(:get, "www.example.com").
#   with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})

Net::HTTP.start('www.example.com') do |http|
  req = Net::HTTP::Get.new('/')
  req.basic_auth 'user', 'pass'
  http.request(req)
end    # ===> Success
Important! Since version 2.0.0, WebMock does not match credentials provided in Authorization header and credentials provided in the userinfo of a url. I.e. stub_request(:get, "user:pass@www.example.com") does not match a request with credentials provided in the Authorization header.

Request with basic authentication in the url

stub_request(:get, "user:pass@www.example.com")

RestClient.get('user:pass@www.example.com')    # ===> Success

Matching uris using regular expressions

stub_request(:any, /example/)

Net::HTTP.get('www.example.com', '/')    # ===> Success

Matching uris using RFC 6570 - Basic Example

uri_template = Addressable::Template.new "www.example.com/{id}/"
stub_request(:any, uri_template)

Net::HTTP.get('www.example.com', '/webmock/')    # ===> Success

Matching uris using RFC 6570 - Advanced Example

uri_template =
  Addressable::Template.new "www.example.com/thing/{id}.json{?x,y,z}{&other*}"
stub_request(:any, uri_template)

Net::HTTP.get('www.example.com',
  '/thing/5.json?x=1&y=2&z=3&anyParam=4')    # ===> Success

Matching query params using hash

stub_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})

RestClient.get("http://www.example.com/?a[]=b&a[]=c")    # ===> Success

Matching partial query params using hash

stub_request(:get, "www.example.com").
  with(query: hash_including({"a" => ["b", "c"]}))

RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1")    # ===> Success

Matching partial query params using hash_excluding

stub_request(:get, "www.example.com").
  with(query: hash_excluding({"a" => "b"}))

RestClient.get("http://www.example.com/?a=b")    # ===> Failure
RestClient.get("http://www.example.com/?a=c")    # ===> Success

Stubbing with custom response

stub_request(:any, "www.example.com").
  to_return(body: "abc", status: 200,
    headers: { 'Content-Length' => 3 })

Net::HTTP.get("www.example.com", '/')    # ===> "abc"

Response with body specified as IO object

File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }

stub_request(:any, "www.example.com").
  to_return(body: File.new('/tmp/response_body.txt'), status: 200)

Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"

Response with custom status message

stub_request(:any, "www.example.com").
  to_return(status: [500, "Internal Server Error"])

req = Net::HTTP::Get.new("/")
Net::HTTP.start("www.example.com") { |http| http.request(req) }.
  message    # ===> "Internal Server Error"

Replaying raw responses recorded with curl -is

curl -is www.example.com > /tmp/example_curl_-is_output.txt
raw_response_file = File.new("/tmp/example_curl_-is_output.txt")

from file

stub_request(:get, "www.example.com").to_return(raw_response_file)

or string

stub_request(:get, "www.example.com").to_return(raw_response_file.read)

Responses dynamically evaluated from block

stub_request(:any, 'www.example.net').
  to_return { |request| {body: request.body} }

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

Responses dynamically evaluated from lambda

stub_request(:any, 'www.example.net').
  to_return(lambda { |request| {body: request.body} })

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

Dynamically evaluated raw responses recorded with curl -is

`curl -is www.example.com > /tmp/www.example.com.txt`
stub_request(:get, "www.example.com").
  to_return(lambda { |request| File.new("/tmp/#{request.uri.host.to_s}.txt") })

Responses with dynamically evaluated parts

stub_request(:any, 'www.example.net').
  to_return(body: lambda { |request| request.body })

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

Rack responses

class MyRackApp
  def self.call(env)
    [200, {}, ["Hello"]]
  end
end

stub_request(:get, "www.example.com").to_rack(MyRackApp)

RestClient.post('www.example.com')    # ===> "Hello"

Multiple responses for repeated requests

stub_request(:get, "www.example.com").
  to_return({body: "abc"}, {body: "def"})
Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"
Net::HTTP.get('www.example.com', '/')    # ===> "def\n"

#after all responses are used the last response will be returned infinitely

Net::HTTP.get('www.example.com', '/')    # ===> "def\n"

Multiple responses using chained to_return(), to_raise() or to_timeout declarations

stub_request(:get, "www.example.com").
  to_return({body: "abc"}).then.  #then() is just a syntactic sugar
  to_return({body: "def"}).then.
  to_raise(MyException)

Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"
Net::HTTP.get('www.example.com', '/')    # ===> "def\n"
Net::HTTP.get('www.example.com', '/')    # ===> MyException raised

Specifying number of times given response should be returned

stub_request(:get, "www.example.com").
  to_return({body: "abc"}).times(2).then.
  to_return({body: "def"})

Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"
Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"
Net::HTTP.get('www.example.com', '/')    # ===> "def\n"
Clone this wiki locally