概要
-
翻訳について
-
ライセンスについて
- webmock のライセンスと同様のライセンスに従います。
目次
-
WebMock
- 機能
- サポートされている HTTP ライブラリ
- サポートされている Ruby インタープリタ
- インストール
- バージョン v1.x から v2.x へのアップグレード
- 例
-
スタブ
- URI のみに基づきかつデフォルトレスポンスをともなったスタブリクエスト
- メソッド、URI、ボディ、ヘッダに基づいたスタブリクエスト
- 正規表現を使用したリクエストボディとヘッダのマッチ
- ハッシュを使用したリクエストボディのマッチ。リクエストボディは URL エンコード、JSON、XML で記述しリクエスト可能です。
- 部分ハッシュを使用したリクエストのマッチ
- カスタムリクエストヘッダのマッチ
- 同じ名前の複数のヘッダのマッチ
- 与えられたブロックを使用したリクエストのマッチ
- BASIC 認証をともなったリクエスト
- URL 内の BASIC 認証をともなったリクエスト
- 正規表現を使用した URI のマッチ
- RFC 6570 を使用した URI のマッチ。基本的な例
- RFC 6570 を使用した URI のマッチ。応用的な例
- ハッシュを使用したクエリパラムのマッチ
- ハッシュを使用した部分的なクエリパラムのマッチ
- hash_excluding メソッドを使用した部分的なクエリパラムのマッチ
- カスタムレスポンスをともなったスタブ
- IO オブジェクトとして指定されたボディをともなったレスポンス
- カスタムステータスメッセージをともなったレスポンス
curl -is
コマンドで記録された未加工のレスポンスを再現する- ブロックから評価される動的なレスポンス
- ラムダから評価される動的なレスポンス
curl -is
で記録された動的に評価された未加工のレスポンス- 一部分が動的評価されているレスポンス
- Rack レスポンス
- エラーを発生させる
- タイムアウトエラーを発生させる
- リクエストの繰り返しにおける複数のレスポンス
to_return()
、to_raise()
、to_timeout
メソッドを連鎖させた複数のレスポンス- 与えられたレスポンスが返却される回数の指定
- 未使用のスタブの解除
- ネットワークへの本物のリクエストの許可、不許可
- ローカルホストへのリクエストは許可しつつ外部へのリクエストは無効にする
- 特定のリクエストは許可しつつ外部へのリクエストは無効にする
- Net::HTTP.start 上のコネクト
- 期待値の設定
- スタブとリクエスト履歴のリセット
- リクエストカウンタのリセット
- WebMock または HTTP クライアントアダプタのみの無効化と有効化
- リクエストのマッチ
- スタブの優先順位
- URI のマッチ
- URI Templates のマッチング
- ヘッダのマッチング
- 本物のリクエストとレスポンスの記録とそのリプレイ
- リクエストのコールバック
- Bugs and Issues
- Issue triage *
- Suggestions
- Development
- Credits
- Background
- Copyright
WebMock
Ruby の HTTP リクエストにおいて期待値のスタブと設定をするライブラリです。
機能
- 低 HTTP クライアントライブラリレベル(HTTP ライブラリを変更してもテストを変更する必要はありません)におけるHTTP リクエストのスタブ。
- HTTP リクエスト上の期待値の設定と確認。
- HTTP メソッド、HTTP URI、HTTP ヘッダ、HTTP ボディをもとにしたリクエストとの一致。
- 異なる表現における同じ URI の優れた一致(エンコード済みの URI と未エンコードの URI も一致させる)
- 異なる表現における同じヘッダの優れた一致。
- Test::Unit のサポート
- RSpec のサポート
- MiniTest のサポート
サポートされている HTTP ライブラリ
- Net::HTTP and libraries based on Net::HTTP (i.e RightHttpConnection, REST Client, HTTParty)
- HTTPClient
- Patron
- EM-HTTP-Request
- Curb (currently only Curb::Easy)
- Typhoeus (currently only Typhoeus::Hydra)
- Excon
- HTTP Gem
- Manticore
- Async::HTTP::Client
サポートされている Ruby インタープリタ
- MRI 2.2
- MRI 2.3
- MRI 2.4
- MRI 2.5
- MRI 2.6
- MRI 2.7
- JRuby
- Rubinius
インストール
gem install webmock
github の master ブランチから最新の開発バージョンをインストールする方法
git clone http://github.com/bblimke/webmock.git
cd webmock
rake install
バージョン v1.x から v2.x へのアップグレード
バージョン 1.x からバージョン 2.x の変更点は CHANGELOG.md に記載されています。
Test::Unit
test/test_helper.rb
に下記のコードを追加してください。
require 'webmock/test_unit'
RSpec
spec/spec_helper
に下記のコードを追加してください。
require 'webmock/rspec'
MiniTest
test/test_helper
に下記のコードを追加してください。
require 'webmock/minitest'
Cucumber
下記を記載した features/support/webmock.rb
を作成してください。
require 'webmock/cucumber'
テストフレームワーク外
テストフレームワーク外でも WebMock を使用することができます。
require 'webmock'
include WebMock::API
WebMock.enable!
例
スタブ
URI のみに基づきかつデフォルトレスポンスをともなったスタブリクエスト
stub_request(:any, "www.example.com")
Net::HTTP.get("www.example.com", "/") # ===> Success
メソッド、URI、ボディ、ヘッダに基づいたスタブリクエスト
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
正規表現を使用したリクエストボディとヘッダのマッチ
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
ハッシュを使用したリクエストボディのマッチ。リクエストボディは URL エンコード、JSON、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
部分ハッシュを使用したリクエストのマッチ
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
カスタムリクエストヘッダのマッチ
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
同じ名前の複数のヘッダのマッチ
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
与えられたブロックを使用したリクエストのマッチ
stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
RestClient.post('www.example.com', 'abc') # ===> Success
BASIC 認証をともなったリクエスト
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
重要事項。バージョン 2.0.0 から、WebMock は Authorization ヘッダ内で与えられるクレデンシャルと URL のユーザー情報の中で与えられるクレデンシャルをマッチさせません。つまり、stub_request(:get, "user:pass@www.example.com")
は Authorization ヘッダで与えられたクレデンシャルをともなったリクエストとマッチしません。
URL 内の BASIC 認証をともなったリクエスト
stub_request(:get, "user:pass@www.example.com")
RestClient.get('user:pass@www.example.com') # ===> Success
正規表現を使用した URI のマッチ
stub_request(:any, /example/)
Net::HTTP.get('www.example.com', '/') # ===> Success
RFC 6570 を使用した URI のマッチ。基本的な例
uri_template = Addressable::Template.new "www.example.com/{id}/"
stub_request(:any, uri_template)
Net::HTTP.get('www.example.com', '/webmock/') # ===> Success
RFC 6570 を使用した URI のマッチ。応用的な例
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
ハッシュを使用したクエリパラムのマッチ
stub_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})
RestClient.get("http://www.example.com/?a[]=b&a[]=c") # ===> Success
ハッシュを使用した部分的なクエリパラムのマッチ
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
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
カスタムレスポンスをともなったスタブ
stub_request(:any, "www.example.com").
to_return(body: "abc", status: 200,
headers: { 'Content-Length' => 3 })
Net::HTTP.get("www.example.com", '/') # ===> "abc"
IO オブジェクトとして指定されたボディをともなったレスポンス
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"
カスタムステータスメッセージをともなったレスポンス
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"
curl -is
コマンドで記録された未加工のレスポンスを再現する
curl -is www.example.com > /tmp/example_curl_-is_output.txt
raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
上記で生成されたファイルを使用する。
stub_request(:get, "www.example.com").to_return(raw_response_file)
string を引数にすることもできる。
stub_request(:get, "www.example.com").to_return(raw_response_file.read)
ブロックから評価される動的なレスポンス
stub_request(:any, 'www.example.net').
to_return { |request| {body: request.body} }
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
ラムダから評価される動的なレスポンス
stub_request(:any, 'www.example.net').
to_return(lambda { |request| {body: request.body} })
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
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") })
一部分が動的評価されているレスポンス
stub_request(:any, 'www.example.net').
to_return(body: lambda { |request| request.body })
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
Rack レスポンス
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"
エラーを発生させる
クラスで宣言された例外
stub_request(:any, 'www.example.net').to_raise(StandardError)
RestClient.post('www.example.net', 'abc') # ===> StandardError
インスタンスによる例外
stub_request(:any, 'www.example.net').to_raise(StandardError.new("some error"))
文字列による例外
stub_request(:any, 'www.example.net').to_raise("some error")
タイムアウトエラーを発生させる
stub_request(:any, 'www.example.net').to_timeout
RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
リクエストの繰り返しにおける複数のレスポンス
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"
# すべてのレスポンスが使用されたあとは最後のレスポンスがずっと返却される。
Net::HTTP.get('www.example.com', '/') # ===> "def\n"
to_return()
、to_raise()
、to_timeout
メソッドを連鎖させた複数のレスポンス
stub_request(:get, "www.example.com").
to_return({body: "abc"}).then. #then() メソッドはシンタックスシュガーです。
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
与えられたレスポンスが返却される回数の指定
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"
未使用のスタブの解除
stub_get = stub_request(:get, "www.example.com")
remove_request_stub(stub_get)
ネットワークへの本物のリクエストの許可、不許可
WebMock.allow_net_connect!
stub_request(:any, "www.example.com").to_return(body: "abc")
Net::HTTP.get('www.example.com', '/') # ===> "abc"
Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
WebMock.disable_net_connect!
Net::HTTP.get('www.something.com', '/') # ===> Failure
ローカルホストへのリクエストは許可しつつ外部へのリクエストは無効にする
WebMock.disable_net_connect!(allow_localhost: true)
Net::HTTP.get('www.something.com', '/') # ===> Failure
Net::HTTP.get('localhost:9887', '/') # ===> Allowed. Perhaps to Selenium?
特定のリクエストは許可しつつ外部へのリクエストは無効にする
許可するリクエストはいくつかの方法で指定することができます。
文字列でホスト名を指定する方法。
WebMock.disable_net_connect!(allow: 'www.example.org')
RestClient.get('www.something.com', '/') # ===> Failure
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('www.example.org:8080', '/') # ===> Allowed
文字列でホスト名とポートを指定する方法。
WebMock.disable_net_connect!(allow: 'www.example.org:8080')
RestClient.get('www.something.com', '/') # ===> Failure
RestClient.get('www.example.org', '/') # ===> Failure
RestClient.get('www.example.org:8080', '/') # ===> Allowed
URI をマッチする正規表現で指定する方法。
WebMock.disable_net_connect!(allow: %r{ample.org/foo})
RestClient.get('www.example.org', '/foo/bar') # ===> Allowed
RestClient.get('sample.org', '/foo') # ===> Allowed
RestClient.get('sample.org', '/bar') # ===> Failure
#call
メソッドに応答し、URI
オブジェクトを受け取りブーリアンを返すオブジェクトを指定する方法。
blacklist = ['google.com', 'facebook.com', 'apple.com']
allowed_sites = lambda{|uri|
blacklist.none?{|site| uri.host.include?(site) }
}
WebMock.disable_net_connect!(allow: allowed_sites)
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('www.facebook.com', '/') # ===> Failure
RestClient.get('apple.com', '/') # ===> Failure
上記のいづれかのオブジェクトが入っている配列。
WebMock.disable_net_connect!(allow: [
lambda{|uri| uri.host.length % 2 == 0 },
/ample.org/,
'bbc.co.uk',
])
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('bbc.co.uk', '/') # ===> Allowed
RestClient.get('bbc.com', '/') # ===> Allowed
RestClient.get('www.bbc.com', '/') # ===> Failure
Net::HTTP.start 上のコネクト
HTTP プロトコルは3つのステップで出来ています。コネクト、リクエスト、レスポンスです(あるいはクローズが4つ目に入ることもあります)。ほとんどの Ruby HTTP クライアントライブラリはリクエストのステップの一部分としてコネクトを扱っていますが、Net::HTTP
は違います。Net::HTTP
は Net::HTTP.start
を使用することによってサーバへのリクエストとは別々にコネクションをオープンすることができます。
WebMock API はリクエストのステップの一部分としてコネクトを行うように作られており、リクエストはスタブしますがコネクトはスタブしません。Net::HTTP.start
が呼び出されたとき、WebMock はリクエストがスタブされるかどうかを知りません。デフォルトでは、WebMock はリクエストが実行されるまでコネクトを遅らせます。そのため、リクエストがないときは、Net::HTTP.start
は何も行いません。
これは、デフォルトでは WebMock は Net::HTTP の動作を中断させることを意味しています。
この問題を解決するために、WebMock は :net_http_connect_on_start
オプションを提供しています。このオプションは WebMock.allow_net_connect!
と WebMock.disable_net_connect!
に渡されます。
WebMock.allow_net_connect!(net_http_connect_on_start: true)
これによって WebMock Net::HTTP adapter は常に Net::HTTP.start
上でコネクトをするようになります。
期待値の設定
Test::Unit の期待値の設定
require 'webmock/test_unit'
stub_request(:any, "www.example.com")
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
assert_requested :post, "http://www.example.com",
headers: {'Content-Length' => 3}, body: "abc",
times: 1 # ===> Success
assert_not_requested :get, "http://www.something.com" # ===> Success
assert_requested(:post, "http://www.example.com",
times: 1) { |req| req.body == "abc" }
スタブではない本当のリクエストの期待
WebMock.allow_net_connect!
Net::HTTP.get('www.example.com', '/') # ===> Success
assert_requested :get, "http://www.example.com" # ===> Success
スタブ上の Test::Unit の期待値の設定
stub_get = stub_request(:get, "www.example.com")
stub_post = stub_request(:post, "www.example.com")
Net::HTTP.get('www.example.com', '/')
assert_requested(stub_get)
assert_not_requested(stub_post)
WebMock
モジュール上の RSpec の期待値の設定
この形式は fakeweb-matcher を参考にしています。
require 'webmock/rspec'
expect(WebMock).to have_requested(:get, "www.example.com").
with(body: "abc", headers: {'Content-Length' => 3}).twice
expect(WebMock).not_to have_requested(:get, "www.something.com")
expect(WebMock).to have_requested(:post, "www.example.com").
with { |req| req.body == "abc" }
# 括弧の代わりに `do ... end` ブロックを使用すると動作しないことに注意してください。
# 理由は https://github.com/bblimke/webmock/issues/174#issuecomment-34908908 をご覧ください。
expect(WebMock).to have_requested(:get, "www.example.com").
with(query: {"a" => ["b", "c"]})
expect(WebMock).to have_requested(:get, "www.example.com").
with(query: hash_including({"a" => ["b", "c"]}))
expect(WebMock).to have_requested(:get, "www.example.com").
with(body: {"a" => ["b", "c"]},
headers: {'Content-Type' => 'application/json'})
a_request
を使用した RSpec の期待値の設定
expect(a_request(:post, "www.example.com").
with(body: "abc", headers: {'Content-Length' => 3})).
to have_been_made.once
expect(a_request(:post, "www.something.com")).to have_been_made.times(3)
expect(a_request(:post, "www.something.com")).to have_been_made.at_least_once
expect(a_request(:post, "www.something.com")).
to have_been_made.at_least_times(3)
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_twice
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_times(3)
expect(a_request(:any, "www.example.com")).not_to have_been_made
expect(a_request(:post, "www.example.com").with { |req| req.body == "abc" }).
to have_been_made
expect(a_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})).
to have_been_made
expect(a_request(:get, "www.example.com").
with(query: hash_including({"a" => ["b", "c"]}))).to have_been_made
expect(a_request(:post, "www.example.com").
with(body: {"a" => ["b", "c"]},
headers: {'Content-Type' => 'application/json'})).to have_been_made
スタブ上の RSpec の期待値の設定
stub = stub_request(:get, "www.example.com")
# ... make requests ...
expect(stub).to have_been_requested
スタブとリクエスト履歴のリセット
すべてのスタブとリクエスト履歴をリセットしたいときは、WebMock.reset!
を使用してください。
stub_request(:any, "www.example.com")
Net::HTTP.get('www.example.com', '/') # ===> Success
WebMock.reset!
Net::HTTP.get('www.example.com', '/') # ===> Failure
assert_not_requested :get, "www.example.com" # ===> Success
リクエストカウンタのリセット
実行済みのリクエストカウンタのみをリセットしたいときは、WebMock.reset_executed_requests!
を使用してください。
stub = stub_request(:get, "www.example.com")
stub2 = stub_request(:get, "www.example2.com")
Net::HTTP.get('www.example.com', '/')
Net::HTTP.get('www.example.com', '/')
Net::HTTP.get('www.example2.com', '/')
expect(stub).to have_been_requested.times(2)
expect(stub2).to have_been_requested.times(1)
WebMock.reset_executed_requests!
expect(stub).not_to have_been_requested
expect(stub2).not_to have_been_requested
WebMock または HTTP クライアントアダプタのみの無効化と有効化
# WebMock の無効化(全アダプタ)
WebMock.disable!
# Net::HTTP を除くすべてのライブラリの WebMock の無効化
WebMock.disable!(except: [:net_http])
# WebMock の有効化(全アダプタ)
WebMock.enable!
# Patron を除くすべてのライブラリの WebMock の有効化
WebMock.enable!(except: [:patron])
リクエストのマッチ
下記の基準を満たすとき、実行されたリクエストはスタブリクエストとマッチします。
- リクエスト URI がスタブリクエストの URI 、正規表現、RFC 6570 URI テンプレートとマッチするとき。
- かつ、リクエストメソッドがスタブクリエストのものと同じとき、あるいはスタブリクエストのメソッドが :any のとき。
- かつ、リクエストボディがスタブクリエストのものと同じとき、あるいはスタブリクエストのボディが指定されていないとき。
- かつ、リクエストヘッダがスタブリクエストヘッダとマッチするとき、あるいはスタブリクエストヘッダがリクエストヘッダのサブセットとマッチするとき、あるいはスタブリクエストヘッダが指定されないとき。
- かつ、リクエストが与えられたブロックにマッチするとき、あるいはブロックが与えられていないとき。
スタブの優先順位
最後に宣言された、リクエストにマッチするスタブが常に適用されます。
stub_request(:get, "www.example.com").to_return(body: "abc")
stub_request(:get, "www.example.com").to_return(body: "def")
Net::HTTP.get('www.example.com', '/') # ====> "def"
URI のマッチ
WebMock は同じ URI のすべての異なった表現形式とマッチします。
下記のすべての URI の表現形式は同じ URI として扱われます。
"www.example.com"
"www.example.com/"
"www.example.com:80"
"www.example.com:80/"
"http://www.example.com"
"http://www.example.com/"
"http://www.example.com:80"
"http://www.example.com:80/"
下記のユーザー情報をともなった URI は同じ URI として扱われます。
"a b:pass@www.example.com"
"a b:pass@www.example.com/"
"a b:pass@www.example.com:80"
"a b:pass@www.example.com:80/"
"http://a b:pass@www.example.com"
"http://a b:pass@www.example.com/"
"http://a b:pass@www.example.com:80"
"http://a b:pass@www.example.com:80/"
"a%20b:pass@www.example.com"
"a%20b:pass@www.example.com/"
"a%20b:pass@www.example.com:80"
"a%20b:pass@www.example.com:80/"
"http://a%20b:pass@www.example.com"
"http://a%20b:pass@www.example.com/"
"http://a%20b:pass@www.example.com:80"
"http://a%20b:pass@www.example.com:80/"
下記も同様です。
"www.example.com/my path/?a=my param&b=c"
"www.example.com/my%20path/?a=my%20param&b=c"
"www.example.com:80/my path/?a=my param&b=c"
"www.example.com:80/my%20path/?a=my%20param&b=c"
"http://www.example.com/my path/?a=my param&b=c"
"http://www.example.com/my%20path/?a=my%20param&b=c"
"http://www.example.com:80/my path/?a=my param&b=c"
"http://www.example.com:80/my%20path/?a=my%20param&b=c"
正規表現を使用して URI をマッチさせる場合、WebMock は同じ URL のすべての有効な形式を使用して URI をマッチさせます。
つまり、www.example.com/my path
と同等とみなすので、/my path/
は www.example.com/my%20path
とマッチします。
URI Templates のマッチング
マッチングのために Addressable::Template を使用している場合は、WebMock は Addressable に対するマッチングルールを延期し、RFC 6570 に従います。
クエリパラメーターをマッチさせるために任意の WebMock のメソッドを使用している場合は、Addressable はベース URI とマッチするために使用され、WebMock はクエリパラメーターとマッチします。
ヘッダのマッチング
下記の状況において WebMock はスタブされたリクエストヘッダを使用してリクエストヘッダとマッチします。
-
スタブリクエストはヘッダを指定されていて、リクエストヘッダはスタブされたヘッダと同じ
スタブされたヘッダ:{ 'Header1' => 'Value1', 'Header2' => 'Value2' }
, リクエストされたヘッダ:{ 'Header1' => 'Value1', 'Header2' => 'Value2' }
-
スタブリクエストはヘッダを指定されていて、スタブされたリクエストヘッダはリクエストヘッダのサブセット
スタブされたヘッダ:{ 'Header1' => 'Value1' }
, リクエストされたヘッダ:{ 'Header1' => 'Value1', 'Header2' => 'Value2' }
-
スタブリクエストがヘッダを持っていない
スタブされたヘッダ:nil
, リクエストされたヘッダ:{ 'Header1' => 'Value1', 'Header2' => 'Value2' }
WebMock はヘッダを標準化し、同じヘッダのすべての形式を同じものとして扱います。
つまり、下記のヘッダの組み合わせは同じものとして扱われます。
{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }
{ header1: "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }
本物のリクエストとレスポンスの記録とそのリプレイ
アプリケーションの本物の HTTP のやり取りを記録し、それをテストの中でリプレイするためには、WebMock とともに gem VCR を使用することができます。
リクエストのコールバック
WebMock はスタブされたあるいは本物のリクエストのコールバックを引き起こすことができる
WebMock.after_request do |request_signature, response|
puts "Request #{request_signature} was made and #{response} was returned"
end
Patron で作成されたリクエストは除き、本物のリクエストのみコールバックを引き起こす
WebMock.after_request(except: [:patron],
real_requests_only: true) do |req_signature, response|
puts "Request #{req_signature} was made and #{response} was returned"
end
Bugs and Issues
Please submit them here http://github.com/bblimke/webmock/issues
Issue triage
You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to subscribe to webmock on CodeTriage.
Suggestions
If you have any suggestions on how to improve WebMock please send an email to the mailing list groups.google.com/group/webmock-users
I'm particularly interested in how the DSL could be improved.
Development
In order to work on Webmock you first need to fork and clone the repo.
Please do any work on a dedicated branch and rebase against master
before sending a pull request.
Credits
The initial lines of this project were written during New Bamboo Hack Day
Thanks to my fellow Bambinos for all the great suggestions!
People who submitted patches and new features or suggested improvements. Many thanks to these people:
- Ben Pickles
- Mark Evans
- Ivan Vega
- Piotr Usewicz
- Nick Plante
- Nick Quaranto
- Diego E. "Flameeyes" Pettenò
- Niels Meersschaert
- Mack Earnhardt
- Arvicco
- Sergio Gil
- Jeffrey Jones
- Tekin Suleyman
- Tom Ward
- Nadim Bitar
- Myron Marston
- Sam Phillips
- Jose Angel Cortinas
- Razic
- Steve Tooke
- Nathaniel Bibler
- Martyn Loughran
- Muness Alrubaie
- Charles Li
- Ryan Bigg
- Pete Higgins
- Hans de Graaff
- Alastair Brunton
- Sam Stokes
- Eugene Bolshakov
- James Conroy-Finn
- Salvador Fuentes Jr
- Alex Rothenberg
- Aidan Feldman
- Steve Hull
- Jay Adkisson
- Zach Dennis
- Nikita Fedyashev
- Lin Jen-Shin
- David Yeu
- Andreas Garnæs
- Roman Shterenzon
- Chris McGrath
- Stephen Celis
- Eugene Pimenov
- Albert Llop
- Christopher Pickslay
- Tammer Saleh
- Nicolas Fouché
- Joe Van Dyk
- Mark Abramov
- Frank Schumacher
- Dimitrij Denissenko
- Marnen Laibow-Koser
- Evgeniy Dolzhenko
- Nick Recobra
- Jordan Elver
- Joe Karayusuf
- Paul Cortens
- jugyo
- aindustries
- Eric Oestrich
- erwanlr
- Ben Bleything
- Jon Leighton
- Ryan Schlesinger
- Julien Boyer
- Kevin Glowacz
- Hans Hasselberg
- Andrew France
- Jonathan Hyman
- Rex Feng
- Pavel Forkert
- Jordi Massaguer Pla
- Jake Benilov
- Tom Beauvais
- Mokevnin Kirill
- Alex Grant
- Lucas Dohmen
- Bastien Vaucher
- Joost Baaij
- Joel Chippindale
- Murahashi Sanemat Kenichi
- Tim Kurvers
- Ilya Vassilevsky
- gotwalt
- Leif Bladt
- Alex Tomlins
- Mitsutaka Mimura
- Tomy Kaira
- Daniel van Hoesel
- Ian Asaff
- Ian Lesperance
- Matthew Horan
- Dmitry Gutov
- Florian Dütsch
- Manuel Meurer
- Brian D. Burns
- Riley Strong
- Tamir Duberstein
- Stefano Uliari
- Alex Stupakov
- Karen Wang
- Matt Burke
- Jon Rowe
- Aleksey V. Zapparov
- Praveen Arimbrathodiyil
- Bo Jeanes
- Matthew Conway
- Rob Olson
- Max Lincoln
- Oleg Gritsenko
- Hwan-Joon Choi
- SHIBATA Hiroshi
- Caleb Thompson
- Theo Hultberg
- Pablo Jairala
- Insoo Buzz Jung
- Carlos Alonso Pérez
- trlorenz
- Alexander Simonov
- Thorbjørn Hermanse
- Mark Lorenz
- tjsousa
- Tasos Stathopoulos
- Dan Buettner
- Sven Riedel
- Mark Lorenz
- Dávid Kovács
- fishermand46
- Franky Wahl
- ChaYoung You
- Simon Russell
- Steve Mitchell
- Mattias Putman
- Zachary Anker
- Emmanuel Sambo
- Ramon Tayag
- Johannes Schlumberger
- Siôn Le Roux
- Matt Palmer
- Zhao Wen
- Krzysztof Rygielski
- Magne Land
- yurivm
- Mike Knepper
- Charles Pence
- Alexey Zapparov
- Pablo Brasero
- Cedric Pimenta
- Michiel Karnebeek
- Alex Kestner
- Manfred Stienstra
- Tim Diggins
- Gabriel Chaney
- Chris Griego
- Taiki Ono
- Jonathan Schatz
- Jose Luis Honorato
- Aaron Kromer
- Pavel Jurašek
- Jake Worth
- Gabe Martin-Dempesy
- Michael Grosser
- Aleksei Maridashvili
- Ville Lautanala
- Koichi ITO
- Jordan Harband
- Tarmo Tänav
- Joe Marty
- Chris Thomson
- Vít Ondruch
- George Ulmer
- Christof Koenig
- Chung-Yi Chi
- Olexandr Hoshylyk
- Janko Marohnić
- Pat Allan
- Rick Song
- NARUSE, Yui
- Piotr Boniecki
- Olia Kremmyda
- Michał Matyas
- Matt Brictson
- Kenny Ortmann
- redbar0n
- Lukas Pokorny
- Arkadiy Tetelman
- Kazato Sugimoto
- Olle Jonsson
- Pavel Rosický
- Geremia Taglialatela
- Koichi Sasada
- Yusuke Endoh
- Grey Baker
- SoonKhen OwYong
- Pavel Valena
- Adam Sokolnicki
- Jeff Felchner
- Eike Send
- Claudio Poli
- Csaba Apagyi
- Frederick Cheung
- Fábio D. Batista
- Andriy Yanko
- y-yagi
- Rafael França
- George Claghorn
- Alex Junger
- Orien Madgwick
- Andrei Sidorov
- Marco Costa
- Ryan Davis
- Brandur
- Samuel Williams
- Patrik Ragnarsson
- Alex Coomans
- Vesa Laakso
For a full list of contributors you can visit the
contributors page.
Background
Thank you Fakeweb! This library was inspired by FakeWeb.
I imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.
Fakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.
I also preferred some things to work differently i.e request stub precedence.
Copyright
Copyright (c) 2009-2010 Bartosz Blimke. See LICENSE for details.