{"id":13463368,"url":"https://github.com/bblimke/webmock","last_synced_at":"2026-04-01T16:47:37.440Z","repository":{"id":716155,"uuid":"363163","full_name":"bblimke/webmock","owner":"bblimke","description":"Library for stubbing and setting expectations on HTTP requests in Ruby.","archived":false,"fork":false,"pushed_at":"2026-03-18T04:06:41.000Z","size":2761,"stargazers_count":4052,"open_issues_count":179,"forks_count":576,"subscribers_count":41,"default_branch":"master","last_synced_at":"2026-03-29T06:54:24.796Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bblimke.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2009-11-06T10:37:29.000Z","updated_at":"2026-03-27T01:00:26.000Z","dependencies_parsed_at":"2024-05-01T13:20:07.440Z","dependency_job_id":"da17206e-aff1-4d57-a072-9b422594386a","html_url":"https://github.com/bblimke/webmock","commit_stats":{"total_commits":1499,"total_committers":283,"mean_commits":5.296819787985866,"dds":0.5790527018012008,"last_synced_commit":"9ff63ac7c845a75278e43236e0128e197f597462"},"previous_names":[],"tags_count":170,"template":false,"template_full_name":null,"purl":"pkg:github/bblimke/webmock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bblimke%2Fwebmock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bblimke%2Fwebmock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bblimke%2Fwebmock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bblimke%2Fwebmock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bblimke","download_url":"https://codeload.github.com/bblimke/webmock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bblimke%2Fwebmock/sbom","scorecard":{"id":227982,"data":{"date":"2025-08-11","repo":{"name":"github.com/bblimke/webmock","commit":"50bb34991864a8155908c261954a3081df795f3e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Code-Review","score":3,"reason":"Found 6/16 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":1,"reason":"0 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/CI.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/CI.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/bblimke/webmock/CI.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/CI.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/bblimke/webmock/CI.yml/master?enable=pin","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T04:11:41.139Z","repository_id":716155,"created_at":"2025-08-17T04:11:41.139Z","updated_at":"2025-08-17T04:11:41.139Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31186078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-30T09:33:56.856Z","status":"ssl_error","status_checked_at":"2026-03-30T09:33:48.185Z","response_time":138,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T13:00:52.130Z","updated_at":"2026-04-01T16:47:37.430Z","avatar_url":"https://github.com/bblimke.png","language":"Ruby","readme":"WebMock\n=======\n[![Gem Version](https://badge.fury.io/rb/webmock.svg)](http://badge.fury.io/rb/webmock)\n[![Build Status](https://github.com/bblimke/webmock/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/bblimke/webmock/actions)\n[![Code Climate](https://codeclimate.com/github/bblimke/webmock/badges/gpa.svg)](https://codeclimate.com/github/bblimke/webmock)\n[![Mentioned in Awesome Ruby](https://awesome.re/mentioned-badge.svg)](https://github.com/markets/awesome-ruby)\n\nLibrary for stubbing and setting expectations on HTTP requests in Ruby.\n\nFeatures\n--------\n\n* Stubbing HTTP requests at low http client lib level (no need to change tests when you change HTTP library)\n* Setting and verifying expectations on HTTP requests\n* Matching requests based on method, URI, headers and body\n* Smart matching of the same URIs in different representations (also encoded and non encoded forms)\n* Smart matching of the same headers in different representations.\n* Support for Test::Unit\n* Support for RSpec\n* Support for MiniTest\n\nSupported HTTP libraries\n------------------------\n\n* [Async::HTTP::Client](https://github.com/socketry/async-http)\n* [Curb](https://github.com/taf2/curb) (currently only Curb::Easy)\n* [EM-HTTP-Request](https://github.com/igrigorik/em-http-request)\n* [Excon](https://github.com/excon/excon)\n* [HTTPClient](https://github.com/nahi/httpclient)\n* [HTTP Gem (also known as http.rb)](https://github.com/httprb/http)\n* [httpx](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter)\n* [Manticore](https://github.com/cheald/manticore)\n* [Net::HTTP](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html) and other libraries based on Net::HTTP, e.g.:\n  * [HTTParty](https://github.com/jnunemaker/httparty)\n  * [REST Client](https://github.com/rest-client/rest-client)\n* [Patron](https://github.com/toland/patron)\n* [Typhoeus](https://github.com/typhoeus/typhoeus) (currently only Typhoeus::Hydra)\n\nSupported Ruby Interpreters\n---------------------------\n* MRI 2.6\n* MRI 2.7\n* MRI 3.0\n* MRI 3.1\n* MRI 3.2\n* MRI 3.3\n* MRI 3.4\n* MRI 4.0\n* JRuby\n\n## Installation\n\n```bash\ngem install webmock\n```\nor alternatively:\n\n```ruby\n# add to your Gemfile\ngroup :test do\n  gem \"webmock\"\nend\n```\n\n### or to install the latest development version from github master\n\n```bash\ngit clone http://github.com/bblimke/webmock.git\ncd webmock\nrake install\n```\n\n## Upgrading from v1.x to v2.x\n\nWebMock 2.x has changed somewhat since version 1.x. Changes are listed in [CHANGELOG.md](CHANGELOG.md)\n\n### Cucumber\n\nCreate a file `features/support/webmock.rb` with the following contents:\n\n```ruby\nrequire 'webmock/cucumber'\n```\n\n### MiniTest\n\nAdd the following code to `test/test_helper`:\n\n```ruby\nrequire 'webmock/minitest'\n```\n\n### RSpec\n\nAdd the following code to `spec/spec_helper`:\n\n```ruby\nrequire 'webmock/rspec'\n```\n\n### Test::Unit\n\nAdd the following code to `test/test_helper.rb`\n\n```ruby\nrequire 'webmock/test_unit'\n```\n\n### Outside a test framework\n\nYou can also use WebMock outside a test framework:\n\n```ruby\nrequire 'webmock'\ninclude WebMock::API\n\nWebMock.enable!\n```\n\n# Examples\n\n## Stubbing\n\n### Stubbed request based on uri only and with the default response\n\n```ruby\nstub_request(:any, \"www.example.com\")\n\nNet::HTTP.get(\"www.example.com\", \"/\")    # ===\u003e Success\n```\n\n### Stubbing requests based on method, uri, body and headers\n\n```ruby\nstub_request(:post, \"www.example.com\").\n  with(body: \"abc\", headers: { 'Content-Length' =\u003e 3 })\n\nuri = URI.parse(\"http://www.example.com/\")\nreq = Net::HTTP::Post.new(uri.path)\nreq['Content-Length'] = 3\n\nres = Net::HTTP.start(uri.host, uri.port) do |http|\n  http.request(req, \"abc\")\nend    # ===\u003e Success\n```\n\n### Matching request body and headers against regular expressions\n\n```ruby\nstub_request(:post, \"www.example.com\").\n  with(body: /world$/, headers: {\"Content-Type\" =\u003e /image\\/.+/}).\n  to_return(body: \"abc\")\n\nuri = URI.parse('http://www.example.com/')\nreq = Net::HTTP::Post.new(uri.path)\nreq['Content-Type'] = 'image/png'\n\nres = Net::HTTP.start(uri.host, uri.port) do |http|\n  http.request(req, 'hello world')\nend    # ===\u003e Success\n```\n\n### Matching request body against a hash. Body can be URL-Encoded, JSON or XML.\n\n```ruby\nstub_request(:post, \"www.example.com\").\n  with(body: {data: {a: '1', b: 'five'}})\n\nRestClient.post('www.example.com', \"data[a]=1\u0026data[b]=five\",\n  content_type: 'application/x-www-form-urlencoded')    # ===\u003e Success\n\nRestClient.post('www.example.com', '{\"data\":{\"a\":\"1\",\"b\":\"five\"}}',\n  content_type: 'application/json')    # ===\u003e Success\n\nRestClient.post('www.example.com', '\u003cdata a=\"1\" b=\"five\" /\u003e',\n  content_type: 'application/xml')    # ===\u003e Success\n```\n\n### Matching request body against partial hash.\n\n```ruby\nstub_request(:post, \"www.example.com\").\n  with(body: hash_including({data: {a: '1', b: 'five'}}))\n\nRestClient.post('www.example.com', \"data[a]=1\u0026data[b]=five\u0026x=1\",\n:content_type =\u003e 'application/x-www-form-urlencoded')    # ===\u003e Success\n```\n\n### Matching custom request headers\n\n```ruby\nstub_request(:any, \"www.example.com\").\n  with(headers:{ 'Header-Name' =\u003e 'Header-Value' })\n\nuri = URI.parse('http://www.example.com/')\nreq = Net::HTTP::Post.new(uri.path)\nreq['Header-Name'] = 'Header-Value'\n\nres = Net::HTTP.start(uri.host, uri.port) do |http|\n  http.request(req, 'abc')\nend    # ===\u003e Success\n```\n\n### Matching multiple headers with the same name\n\n```ruby\nstub_request(:get, 'www.example.com').\n  with(headers: {'Accept' =\u003e ['image/jpeg', 'image/png'] })\n\nreq = Net::HTTP::Get.new(\"/\")\nreq['Accept'] = ['image/png']\nreq.add_field('Accept', 'image/jpeg')\nNet::HTTP.start(\"www.example.com\") {|http| http.request(req) }    # ===\u003e Success\n```\n\n### Matching requests against provided block\n\n```ruby\nstub_request(:post, \"www.example.com\").with { |request| request.body == \"abc\" }\nRestClient.post('www.example.com', 'abc')    # ===\u003e Success\n```\n\n### Request with basic authentication header\n\n```ruby\nstub_request(:get, \"www.example.com\").with(basic_auth: ['user', 'pass'])\n# or\n# stub_request(:get, \"www.example.com\").\n#   with(headers: {'Authorization' =\u003e \"Basic #{ Base64.strict_encode64('user:pass').chomp}\"})\n\nNet::HTTP.start('www.example.com') do |http|\n  req = Net::HTTP::Get.new('/')\n  req.basic_auth 'user', 'pass'\n  http.request(req)\nend    # ===\u003e Success\n```\n\n##### 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.\n\n### Request with basic authentication in the url\n\n```ruby\nstub_request(:get, \"user:pass@www.example.com\")\n\nRestClient.get('user:pass@www.example.com')    # ===\u003e Success\n```\n\n### Matching uris using regular expressions\n\n```ruby\nstub_request(:any, /example/)\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e Success\n```\n\n### Matching uris using lambda\n\n```ruby\nstub_request(:any, -\u003e(uri) { true })\n```\n\n### Matching uris using RFC 6570 - Basic Example\n\n```ruby\nuri_template = Addressable::Template.new \"www.example.com/{id}/\"\nstub_request(:any, uri_template)\n\nNet::HTTP.get('www.example.com', '/webmock/')    # ===\u003e Success\n```\n\n### Matching uris using RFC 6570 - Advanced Example\n\n```ruby\nuri_template =\n  Addressable::Template.new \"www.example.com/thing/{id}.json{?x,y,z}{\u0026other*}\"\nstub_request(:any, uri_template)\n\nNet::HTTP.get('www.example.com',\n  '/thing/5.json?x=1\u0026y=2\u0026z=3\u0026anyParam=4')    # ===\u003e Success\n```\n\n### Matching query params using hash\n\n```ruby\nstub_request(:get, \"www.example.com\").with(query: {\"a\" =\u003e [\"b\", \"c\"]})\n\nRestClient.get(\"http://www.example.com/?a[]=b\u0026a[]=c\")    # ===\u003e Success\n```\n\n### Matching partial query params using hash\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  with(query: hash_including({\"a\" =\u003e [\"b\", \"c\"]}))\n\nRestClient.get(\"http://www.example.com/?a[]=b\u0026a[]=c\u0026x=1\")    # ===\u003e Success\n```\n\n### Matching partial query params using hash_excluding\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  with(query: hash_excluding({\"a\" =\u003e \"b\"}))\n\nRestClient.get(\"http://www.example.com/?a=b\")    # ===\u003e Failure\nRestClient.get(\"http://www.example.com/?a=c\")    # ===\u003e Success\n```\n\n### Stubbing with custom response\n\n```ruby\nstub_request(:any, \"www.example.com\").\n  to_return(body: \"abc\", status: 200,\n    headers: { 'Content-Length' =\u003e 3 })\n\nNet::HTTP.get(\"www.example.com\", '/')    # ===\u003e \"abc\"\n```\n\nSet appropriate Content-Type for HTTParty's `parsed_response`.\n\n```ruby\nstub_request(:any, \"www.example.com\").to_return body: '{}', headers: {content_type: 'application/json'}\n```\n\n### Response with body specified as IO object\n\n```ruby\nFile.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }\n\nstub_request(:any, \"www.example.com\").\n  to_return(body: File.new('/tmp/response_body.txt'), status: 200)\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\\n\"\n```\n\n### Response with JSON body\n\n```ruby\n\nstub_request(:any, \"www.example.com\").\n  to_return_json(body: {foo: \"bar\"})\n\nNet::HTTP.get('www.example.com', '/') # ===\u003e \"{\\\"foo\\\": \\\"bar\\\"}\"\n```\n\n### Response with custom status message\n\n```ruby\nstub_request(:any, \"www.example.com\").\n  to_return(status: [500, \"Internal Server Error\"])\n\nreq = Net::HTTP::Get.new(\"/\")\nNet::HTTP.start(\"www.example.com\") { |http| http.request(req) }.\n  message    # ===\u003e \"Internal Server Error\"\n```\n\n### Replaying raw responses recorded with `curl -is`\n\n```\ncurl -is www.example.com \u003e /tmp/example_curl_-is_output.txt\n```\n\n```ruby\nraw_response_file = File.new(\"/tmp/example_curl_-is_output.txt\")\n```\n\n   from file\n\n```ruby\nstub_request(:get, \"www.example.com\").to_return(raw_response_file)\n```\n\n   or string\n\n```ruby\nstub_request(:get, \"www.example.com\").to_return(raw_response_file.read)\n```\n\n### Responses dynamically evaluated from block\n\n```ruby\nstub_request(:any, 'www.example.net').\n  to_return { |request| {body: request.body} }\n\nRestClient.post('www.example.net', 'abc')    # ===\u003e \"abc\\n\"\n```\n\n### Responses dynamically evaluated from lambda\n\n```ruby\nstub_request(:any, 'www.example.net').\n  to_return(lambda { |request| {body: request.body} })\n\nRestClient.post('www.example.net', 'abc')    # ===\u003e \"abc\\n\"\n```\n\n### Dynamically evaluated raw responses recorded with `curl -is`\n\n`curl -is www.example.com \u003e /tmp/www.example.com.txt`\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  to_return(lambda { |request| File.new(\"/tmp/#{request.uri.host.to_s}.txt\") })\n```\n\n### Responses with dynamically evaluated parts\n\n```ruby\nstub_request(:any, 'www.example.net').\n  to_return(body: lambda { |request| request.body })\n\nRestClient.post('www.example.net', 'abc')    # ===\u003e \"abc\\n\"\n```\n\n### Rack responses\n\n```ruby\nclass MyRackApp\n  def self.call(env)\n    [200, {}, [\"Hello\"]]\n  end\nend\n\nstub_request(:get, \"www.example.com\").to_rack(MyRackApp)\n\nRestClient.post('www.example.com')    # ===\u003e \"Hello\"\n```\n\n### Raising errors\n\n#### Exception declared by class\n\n```ruby\nstub_request(:any, 'www.example.net').to_raise(StandardError)\n\nRestClient.post('www.example.net', 'abc')    # ===\u003e StandardError\n```\n\n#### or by exception instance\n\n```ruby\nstub_request(:any, 'www.example.net').to_raise(StandardError.new(\"some error\"))\n```\n\n#### or by string\n\n```ruby\nstub_request(:any, 'www.example.net').to_raise(\"some error\")\n```\n\n### Raising timeout errors\n\n```ruby\nstub_request(:any, 'www.example.net').to_timeout\n\nRestClient.post('www.example.net', 'abc')    # ===\u003e RestClient::RequestTimeout\n```\n\n### Multiple responses for repeated requests\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  to_return({body: \"abc\"}, {body: \"def\"})\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\\n\"\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"def\\n\"\n\n#after all responses are used the last response will be returned infinitely\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"def\\n\"\n```\n\n### Multiple responses using chained `to_return()`, `to_raise()` or `to_timeout` declarations\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  to_return({body: \"abc\"}).then.  #then() is just a syntactic sugar\n  to_return({body: \"def\"}).then.\n  to_raise(MyException)\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\\n\"\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"def\\n\"\nNet::HTTP.get('www.example.com', '/')    # ===\u003e MyException raised\n```\n\n### Specifying number of times given response should be returned\n\n```ruby\nstub_request(:get, \"www.example.com\").\n  to_return({body: \"abc\"}).times(2).then.\n  to_return({body: \"def\"})\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\\n\"\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\\n\"\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"def\\n\"\n```\n\n### Removing unused stubs\n\n```ruby\nstub_get = stub_request(:get, \"www.example.com\")\nremove_request_stub(stub_get)\n```\n\n### Real requests to network can be allowed or disabled\n\n```ruby\nWebMock.allow_net_connect!\n\nstub_request(:any, \"www.example.com\").to_return(body: \"abc\")\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e \"abc\"\n\nNet::HTTP.get('www.something.com', '/')    # ===\u003e /.+Something.+/\n\nWebMock.disable_net_connect!\n\nNet::HTTP.get('www.something.com', '/')    # ===\u003e Failure\n```\n\n### External requests can be disabled while allowing localhost\n\n```ruby\nWebMock.disable_net_connect!(allow_localhost: true)\n\nNet::HTTP.get('www.something.com', '/')    # ===\u003e Failure\n\nNet::HTTP.get('localhost:9887', '/')    # ===\u003e Allowed. Perhaps to Selenium?\n```\n\n### External requests can be disabled while allowing specific requests\n\nAllowed requests can be specified in a number of ways.\n\nWith a `String` specifying a host name:\n\n```ruby\nWebMock.disable_net_connect!(allow: 'www.example.org')\n\nRestClient.get('www.something.com', '/')    # ===\u003e Failure\nRestClient.get('www.example.org', '/')      # ===\u003e Allowed\nRestClient.get('www.example.org:8080', '/') # ===\u003e Allowed\n```\n\nWith a `String` specifying a host name and a port:\n\n```ruby\nWebMock.disable_net_connect!(allow: 'www.example.org:8080')\n\nRestClient.get('www.something.com', '/')    # ===\u003e Failure\nRestClient.get('www.example.org', '/')      # ===\u003e Failure\nRestClient.get('www.example.org:8080', '/') # ===\u003e Allowed\n```\n\nWith a `Regexp` matching the URI:\n\n```ruby\nWebMock.disable_net_connect!(allow: %r{ample\\.org/foo})\n\nRestClient.get('www.example.org', '/foo/bar') # ===\u003e Allowed\nRestClient.get('sample.org', '/foo')          # ===\u003e Allowed\nRestClient.get('sample.org', '/bar')          # ===\u003e Failure\n```\n\nWith an object that responds to `#call`, receiving a `URI` object and returning a boolean:\n\n```ruby\ndenylist = ['google.com', 'facebook.com', 'apple.com']\nallowed_sites = lambda{|uri|\n  denylist.none?{|site| uri.host.include?(site) }\n}\nWebMock.disable_net_connect!(allow: allowed_sites)\n\nRestClient.get('www.example.org', '/')  # ===\u003e Allowed\nRestClient.get('www.facebook.com', '/') # ===\u003e Failure\nRestClient.get('apple.com', '/')        # ===\u003e Failure\n```\n\nWith an `Array` of any of the above:\n\n```ruby\nWebMock.disable_net_connect!(allow: [\n  lambda{|uri| uri.host.length % 2 == 0 },\n  /ample.org/,\n  'bbc.co.uk',\n])\n\nRestClient.get('www.example.org', '/') # ===\u003e Allowed\nRestClient.get('bbc.co.uk', '/')       # ===\u003e Allowed\nRestClient.get('bbc.com', '/')         # ===\u003e Allowed\nRestClient.get('www.bbc.com', '/')     # ===\u003e Failure\n```\n\n## Connecting on Net::HTTP.start\n\nHTTP protocol has 3 steps: connect, request and response (or 4 with close). Most Ruby HTTP client libraries\ntreat connect as a part of request step, with the exception of `Net::HTTP` which\nallows opening connection to the server separately to the request, by using `Net::HTTP.start`.\n\nWebMock API was also designed with connect being part of request step, and it only allows stubbing\nrequests, not connections. When `Net::HTTP.start` is called, WebMock doesn't know yet whether\na request is stubbed or not. WebMock by default delays a connection until the request is invoked,\nso when there is no request, `Net::HTTP.start` doesn't do anything.\n**This means that WebMock breaks the Net::HTTP behaviour by default!**\n\nTo workaround this issue, WebMock offers `:net_http_connect_on_start` option,\nwhich can be passed to `WebMock.allow_net_connect!` and `WebMock.disable_net_connect!` methods, i.e.\n\n```ruby\nWebMock.allow_net_connect!(net_http_connect_on_start: true)\n```\n\nThis forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`. At the time of connection being made there is no information about the request or URL yet, therefore WebMock is not able to decide whether to stub a request or not and all connections are allowed. To enable connections only to a specific domain (e.g. your test server) use:\n\n```ruby\nWebMock.allow_net_connect!(net_http_connect_on_start: \"www.example.com\")\n```\n\n## Setting Expectations\n\n### Setting expectations in Test::Unit\n\n```ruby\nrequire 'webmock/test_unit'\n\nstub_request(:any, \"www.example.com\")\n\nuri = URI.parse('http://www.example.com/')\nreq = Net::HTTP::Post.new(uri.path)\nreq['Content-Length'] = 3\n\nres = Net::HTTP.start(uri.host, uri.port) do |http|\n  http.request(req, 'abc')\nend\n\nassert_requested :post, \"http://www.example.com\",\n  headers: {'Content-Length' =\u003e 3}, body: \"abc\",\n  times: 1    # ===\u003e Success\n\nassert_not_requested :get, \"http://www.something.com\"    # ===\u003e Success\n\nassert_requested(:post, \"http://www.example.com\",\n  times: 1) { |req| req.body == \"abc\" }\n```\n\n### Expecting real (not stubbed) requests\n\n```ruby\nWebMock.allow_net_connect!\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e Success\n\nassert_requested :get, \"http://www.example.com\"    # ===\u003e Success\n```\n\n### Setting expectations in Test::Unit on the stub\n\n```ruby\nstub_get = stub_request(:get, \"www.example.com\")\nstub_post = stub_request(:post, \"www.example.com\")\n\nNet::HTTP.get('www.example.com', '/')\n\nassert_requested(stub_get)\nassert_not_requested(stub_post)\n```\n\n\n### Setting expectations in RSpec on `WebMock` module\n This style is borrowed from [fakeweb-matcher](http://github.com/pat/fakeweb-matcher)\n\n```ruby\nrequire 'webmock/rspec'\n\nexpect(WebMock).to have_requested(:get, \"www.example.com\").\n  with(body: \"abc\", headers: {'Content-Length' =\u003e 3}).twice\n\nexpect(WebMock).not_to have_requested(:get, \"www.something.com\")\n\nexpect(WebMock).to have_requested(:post, \"www.example.com\").\n  with { |req| req.body == \"abc\" }\n# Note that the block with `do ... end` instead of curly brackets won't work!\n# Why? See this comment https://github.com/bblimke/webmock/issues/174#issuecomment-34908908\n\nexpect(WebMock).to have_requested(:get, \"www.example.com\").\n  with(query: {\"a\" =\u003e [\"b\", \"c\"]})\n\nexpect(WebMock).to have_requested(:get, \"www.example.com\").\n  with(query: hash_including({\"a\" =\u003e [\"b\", \"c\"]}))\n\nexpect(WebMock).to have_requested(:get, \"www.example.com\").\n  with(body: {\"a\" =\u003e [\"b\", \"c\"]},\n    headers: {'Content-Type' =\u003e 'application/json'})\n```\n\n### Setting expectations in RSpec with `a_request`\n\n```ruby\nexpect(a_request(:post, \"www.example.com\").\n  with(body: \"abc\", headers: {'Content-Length' =\u003e 3})).\n  to have_been_made.once\n\nexpect(a_request(:post, \"www.something.com\")).to have_been_made.times(3)\n\nexpect(a_request(:post, \"www.something.com\")).to have_been_made.at_least_once\n\nexpect(a_request(:post, \"www.something.com\")).\n  to have_been_made.at_least_times(3)\n\nexpect(a_request(:post, \"www.something.com\")).to have_been_made.at_most_twice\n\nexpect(a_request(:post, \"www.something.com\")).to have_been_made.at_most_times(3)\n\nexpect(a_request(:any, \"www.example.com\")).not_to have_been_made\n\nexpect(a_request(:post, \"www.example.com\").with { |req| req.body == \"abc\" }).\n  to have_been_made\n\nexpect(a_request(:get, \"www.example.com\").with(query: {\"a\" =\u003e [\"b\", \"c\"]})).\n  to have_been_made\n\nexpect(a_request(:get, \"www.example.com\").\n  with(query: hash_including({\"a\" =\u003e [\"b\", \"c\"]}))).to have_been_made\n\nexpect(a_request(:post, \"www.example.com\").\n  with(body: {\"a\" =\u003e [\"b\", \"c\"]},\n    headers: {'Content-Type' =\u003e 'application/json'})).to have_been_made\n```\n\n### Setting expectations in RSpec on the stub\n\n```ruby\nstub = stub_request(:get, \"www.example.com\")\n# ... make requests ...\nexpect(stub).to have_been_requested\n```\n\n## Clearing stubs and request history\n\nIf you want to reset all current stubs and history of requests use `WebMock.reset!`\n\n```ruby\nstub_request(:any, \"www.example.com\")\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e Success\n\nWebMock.reset!\n\nNet::HTTP.get('www.example.com', '/')    # ===\u003e Failure\n\nassert_not_requested :get, \"www.example.com\"    # ===\u003e Success\n```\n\n## Clearing request counters\n\nIf you want to reset **only** the counters of the executed requests use `WebMock.reset_executed_requests!`\n\n```ruby\nstub  = stub_request(:get, \"www.example.com\")\nstub2 = stub_request(:get, \"www.example2.com\")\n\nNet::HTTP.get('www.example.com', '/')\nNet::HTTP.get('www.example.com', '/')\n\nNet::HTTP.get('www.example2.com', '/')\n\nexpect(stub).to have_been_requested.times(2)\nexpect(stub2).to have_been_requested.times(1)\n\nWebMock.reset_executed_requests!\n\nexpect(stub).not_to have_been_requested\nexpect(stub2).not_to have_been_requested\n```\n\n## Disabling and enabling WebMock or only some http client adapters\n\n```ruby\n# Disable WebMock (all adapters)\nWebMock.disable!\n\n# Disable WebMock for all libs except Net::HTTP\nWebMock.disable!(except: [:net_http])\n\n# Enable WebMock (all adapters)\nWebMock.enable!\n\n# Enable WebMock for all libs except Patron\nWebMock.enable!(except: [:patron])\n```\n\n## Matching requests\n\nAn executed request matches stubbed request if it passes following criteria:\n\n- When request URI matches stubbed request URI string, Regexp pattern or RFC 6570 URI Template\n- And request method is the same as stubbed request method or stubbed request method is :any\n- And request body is the same as stubbed request body or stubbed request body is not specified\n- And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified\n- And request matches provided block or block is not provided\n\n## Precedence of stubs\n\nAlways the last declared stub matching the request will be applied i.e:\n\n```ruby\nstub_request(:get, \"www.example.com\").to_return(body: \"abc\")\nstub_request(:get, \"www.example.com\").to_return(body: \"def\")\n\nNet::HTTP.get('www.example.com', '/')    # ====\u003e \"def\"\n```\n\n## Matching URIs\n\nWebMock will match all different representations of the same URI.\n\nI.e all the following representations of the URI are equal:\n\n```ruby\n\"www.example.com\"\n\"www.example.com/\"\n\"www.example.com:80\"\n\"www.example.com:80/\"\n\"http://www.example.com\"\n\"http://www.example.com/\"\n\"http://www.example.com:80\"\n\"http://www.example.com:80/\"\n```\n\nThe following URIs with userinfo are also equal for WebMock\n\n```ruby\n\"a b:pass@www.example.com\"\n\"a b:pass@www.example.com/\"\n\"a b:pass@www.example.com:80\"\n\"a b:pass@www.example.com:80/\"\n\"http://a b:pass@www.example.com\"\n\"http://a b:pass@www.example.com/\"\n\"http://a b:pass@www.example.com:80\"\n\"http://a b:pass@www.example.com:80/\"\n\"a%20b:pass@www.example.com\"\n\"a%20b:pass@www.example.com/\"\n\"a%20b:pass@www.example.com:80\"\n\"a%20b:pass@www.example.com:80/\"\n\"http://a%20b:pass@www.example.com\"\n\"http://a%20b:pass@www.example.com/\"\n\"http://a%20b:pass@www.example.com:80\"\n\"http://a%20b:pass@www.example.com:80/\"\n```\n\nor these\n\n```ruby\n\"www.example.com/my path/?a=my param\u0026b=c\"\n\"www.example.com/my%20path/?a=my%20param\u0026b=c\"\n\"www.example.com:80/my path/?a=my param\u0026b=c\"\n\"www.example.com:80/my%20path/?a=my%20param\u0026b=c\"\n\"http://www.example.com/my path/?a=my param\u0026b=c\"\n\"http://www.example.com/my%20path/?a=my%20param\u0026b=c\"\n\"http://www.example.com:80/my path/?a=my param\u0026b=c\"\n\"http://www.example.com:80/my%20path/?a=my%20param\u0026b=c\"\n```\n\nIf you provide Regexp to match URI, WebMock will try to match it against every valid form of the same url.\n\nI.e `/my path/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`\n\n## Matching with URI Templates\n\nIf you use [Addressable::Template](https://github.com/sporkmonger/addressable#uri-templates) for matching, then WebMock will defer the matching rules to Addressable, which complies with [RFC 6570](http://tools.ietf.org/html/rfc6570).\n\nIf you use any of the WebMock methods for matching query params, then Addressable will be used to match the base URI and WebMock will match the query params.  If you do not, then WebMock will let Addressable match the full URI.\n\n## Matching headers\n\nWebMock will match request headers against stubbed request headers in the following situations:\n\n1. Stubbed request has headers specified and request headers are the same as stubbed headers \u003cbr/\u003e\ni.e stubbed headers: `{ 'Header1' =\u003e 'Value1', 'Header2' =\u003e 'Value2' }`, requested: `{ 'Header1' =\u003e 'Value1', 'Header2' =\u003e 'Value2' }`\n\n2. Stubbed request has headers specified and stubbed request headers are a subset of request headers \u003cbr/\u003e\ni.e stubbed headers: `{ 'Header1' =\u003e 'Value1'  }`, requested: `{ 'Header1' =\u003e 'Value1', 'Header2' =\u003e 'Value2' }`\n\n3. Stubbed request has no headers \u003cbr/\u003e\ni.e stubbed headers: `nil`, requested: `{ 'Header1' =\u003e 'Value1', 'Header2' =\u003e 'Value2' }`\n\nWebMock normalises headers and treats all forms of same headers as equal:\ni.e the following two sets of headers are equal:\n\n`{ \"Header1\" =\u003e \"value1\", content_length: 123, X_CuStOm_hEAder: :value }`\n\n`{ header1: \"value1\",  \"Content-Length\" =\u003e 123, \"x-cuSTOM-HeAder\" =\u003e \"value\" }`\n\n## Recording real requests and responses and replaying them later\n\nTo record your application's real HTTP interactions and replay them later in tests you can use [VCR](https://github.com/vcr/vcr) with WebMock.\n\n## Request callbacks\n\n#### WebMock can invoke callbacks stubbed or real requests:\n\n```ruby\nWebMock.after_request do |request_signature, response|\n  puts \"Request #{request_signature} was made and #{response} was returned\"\nend\n```\n\n#### invoke callbacks for real requests only and except requests made with Patron\n\n```ruby\nWebMock.after_request(except: [:patron],\n                      real_requests_only: true) do |req_signature, response|\n  puts \"Request #{req_signature} was made and #{response} was returned\"\nend\n```\n\n## Bugs and Issues\n\nPlease submit them here [http://github.com/bblimke/webmock/issues](http://github.com/bblimke/webmock/issues)\n\n## Issue triage [![Open Source Helpers](https://www.codetriage.com/bblimke/webmock/badges/users.svg)](https://www.codetriage.com/bblimke/webmock)\n\nYou 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](https://www.codetriage.com/bblimke/webmock).\n\n## Suggestions\n\nIf you have any suggestions on how to improve WebMock please send an email to the mailing list [groups.google.com/group/webmock-users](http://groups.google.com/group/webmock-users)\n\nI'm particularly interested in how the DSL could be improved.\n\n## Development\n\nIn order to work on Webmock you first need to fork and clone the repo.\nPlease do any work on a dedicated branch and rebase against master\nbefore sending a pull request.\n\n## Credits\n\nThe initial lines of this project were written during New Bamboo [Hack Day](http://blog.new-bamboo.co.uk/2009/11/13/hackday-results)\nThanks to my fellow [Bambinos](http://new-bamboo.co.uk/) for all the great suggestions!\n\nPeople who submitted patches and new features or suggested improvements. Many thanks to these people:\n\n* Ben Pickles\n* Mark Evans\n* Ivan Vega\n* Piotr Usewicz\n* Nick Plante\n* Nick Quaranto\n* Diego E. \"Flameeyes\" Pettenò\n* Niels Meersschaert\n* Mack Earnhardt\n* Arvicco\n* Sergio Gil\n* Jeffrey Jones\n* Tekin Suleyman\n* Tom Ward\n* Nadim Bitar\n* Myron Marston\n* Sam Phillips\n* Jose Angel Cortinas\n* Razic\n* Steve Tooke\n* Nathaniel Bibler\n* Martyn Loughran\n* Muness Alrubaie\n* Charles Li\n* Ryan Bigg\n* Pete Higgins\n* Hans de Graaff\n* Alastair Brunton\n* Sam Stokes\n* Eugene Bolshakov\n* James Conroy-Finn\n* Salvador Fuentes Jr\n* Alex Rothenberg\n* Aidan Feldman\n* Steve Hull\n* Jay Adkisson\n* Zach Dennis\n* Nikita Fedyashev\n* Lin Jen-Shin\n* David Yeu\n* Andreas Garnæs\n* Roman Shterenzon\n* Chris McGrath\n* Stephen Celis\n* Eugene Pimenov\n* Albert Llop\n* Christopher Pickslay\n* Tammer Saleh\n* Nicolas Fouché\n* Joe Van Dyk\n* Mark Abramov\n* Frank Schumacher\n* Dimitrij Denissenko\n* Marnen Laibow-Koser\n* Evgeniy Dolzhenko\n* Nick Recobra\n* Jordan Elver\n* Joe Karayusuf\n* Paul Cortens\n* jugyo\n* aindustries\n* Eric Oestrich\n* erwanlr\n* Ben Bleything\n* Jon Leighton\n* Ryan Schlesinger\n* Julien Boyer\n* Kevin Glowacz\n* Hans Hasselberg\n* Andrew France\n* Jonathan Hyman\n* Rex Feng\n* Pavel Forkert\n* Jordi Massaguer Pla\n* Jake Benilov\n* Tom Beauvais\n* Mokevnin Kirill\n* Alex Grant\n* Lucas Dohmen\n* Bastien Vaucher\n* Joost Baaij\n* Joel Chippindale\n* Murahashi Sanemat Kenichi\n* Tim Kurvers\n* Ilya Vassilevsky\n* gotwalt\n* Leif Bladt\n* Alex Tomlins\n* Mitsutaka Mimura\n* Tomy Kaira\n* Daniel van Hoesel\n* Ian Asaff\n* Ian Lesperance\n* Matthew Horan\n* Dmitry Gutov\n* Florian Dütsch\n* Manuel Meurer\n* Brian D. Burns\n* Riley Strong\n* Tamir Duberstein\n* Stefano Uliari\n* Alex Stupakov\n* Karen Wang\n* Matt Burke\n* Jon Rowe\n* Aleksey V. Zapparov\n* Praveen Arimbrathodiyil\n* Bo Jeanes\n* Matthew Conway\n* Rob Olson\n* Max Lincoln\n* Oleg Gritsenko\n* Hwan-Joon Choi\n* SHIBATA Hiroshi\n* Caleb Thompson\n* Theo Hultberg\n* Pablo Jairala\n* Insoo Buzz Jung\n* Carlos Alonso Pérez\n* trlorenz\n* Alexander Simonov\n* Thorbjørn Hermanse\n* Mark Lorenz\n* tjsousa\n* Tasos Stathopoulos\n* Dan Buettner\n* Sven Riedel\n* Mark Lorenz\n* Dávid Kovács\n* fishermand46\n* Franky Wahl\n* ChaYoung You\n* Simon Russell\n* Steve Mitchell\n* Mattias Putman\n* Zachary Anker\n* Emmanuel Sambo\n* Ramon Tayag\n* Johannes Schlumberger\n* Siôn Le Roux\n* Matt Palmer\n* Zhao Wen\n* Krzysztof Rygielski\n* Magne Land\n* yurivm\n* Mike Knepper\n* Charles Pence\n* Alexey Zapparov\n* Pablo Brasero\n* Cedric Pimenta\n* Michiel Karnebeek\n* Alex Kestner\n* Manfred Stienstra\n* Tim Diggins\n* Gabriel Chaney\n* Chris Griego\n* Taiki Ono\n* Jonathan Schatz\n* Jose Luis Honorato\n* Aaron Kromer\n* Pavel Jurašek\n* Jake Worth\n* Gabe Martin-Dempesy\n* Michael Grosser\n* Aleksei Maridashvili\n* Ville Lautanala\n* Koichi ITO\n* Jordan Harband\n* Tarmo Tänav\n* Joe Marty\n* Chris Thomson\n* Vít Ondruch\n* George Ulmer\n* Christof Koenig\n* Chung-Yi Chi\n* Olexandr Hoshylyk\n* Janko Marohnić\n* Pat Allan\n* Rick Song\n* NARUSE, Yui\n* Piotr Boniecki\n* Olia Kremmyda\n* Michał Matyas\n* Matt Brictson\n* Kenny Ortmann\n* redbar0n\n* Lukas Pokorny\n* Arkadiy Tetelman\n* Kazato Sugimoto\n* Olle Jonsson\n* Pavel Rosický\n* Geremia Taglialatela\n* Koichi Sasada\n* Yusuke Endoh\n* Grey Baker\n* SoonKhen OwYong\n* Pavel Valena\n* Adam Sokolnicki\n* Jeff Felchner\n* Eike Send\n* Claudio Poli\n* Csaba Apagyi\n* Frederick Cheung\n* Fábio D. Batista\n* Andriy Yanko\n* y-yagi\n* Rafael França\n* George Claghorn\n* Alex Junger\n* Orien Madgwick\n* Andrei Sidorov\n* Marco Costa\n* Ryan Davis\n* Brandur\n* Samuel Williams\n* Patrik Ragnarsson\n* Alex Coomans\n* Vesa Laakso\n* John Hawthorn\n* guppy0356\n* Thilo Rusche\n* Andrew Stuntz\n* Lucas Uyezu\n* Bruno Sutic\n* Ryan Kerr\n* Adam Harwood\n* Ben Koshy\n* Jesse Bowes\n* Marek Kasztelnik\n* ce07c3\n* Jun Jiang\n* Oleksiy Kovyrin\n* Matt Larraz\n* Tony Schneider\n* Niklas Hösl\n* Johanna Hartmann\n* Alex Vondrak\n* Will Storey\n* Eduardo Hernandez\n* ojab\n* Giorgio Gambino\n* Timmitry\n* Michael Fairley\n* Ray Zane\n* Go Sueyoshi\n* Cedric Sohrauer\n* Akira Matsuda\n* Mark Spangler\n* Henrik Nyh\n* Yoann Lecuyer\n* Lucas Arnaud\n* Marc Rohloff\n* inkstak\n* Yuki Inoue\n* Brandon Weaver\n* Josh Nichols\n* Ricardo Trindade\n* Earlopain\n* James Brown\n* Kazuhiro NISHIYAMA\n* Étienne Barrié\n* Matt Brown\n* Victor Maslov\n* Gio Lodi\n* Ryan Brooks\n* Jacob Frautschi\n* Christian Schmidt\n* Rodrigo Argumedo\n* Patrick Jaberg\n* Oleg\n* Mikhail Doronin\n* Christoph Rieß\n* Erik Berlin\n\nFor a full list of contributors you can visit the\n[contributors](https://github.com/bblimke/webmock/contributors) page.\n\n## Background\n\nThank you Fakeweb! This library was inspired by [FakeWeb](https://github.com/chrisk/fakeweb).\nI imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.\nFakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.\nI also preferred some things to work differently i.e request stub precedence.\n\n## Copyright\n\nCopyright (c) 2009-2010 Bartosz Blimke. See LICENSE for details.\n","funding_links":[],"categories":["Testing","Ruby","Uncategorized"],"sub_categories":["Mocking Web Requests","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbblimke%2Fwebmock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbblimke%2Fwebmock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbblimke%2Fwebmock/lists"}