Biblioteca para retirar y establecer expectativas en las solicitudes HTTP en Ruby.
Solicitudes de HTTP a nivel de cliente HTTP bajo (no es necesario cambiar las pruebas cuando cambia la biblioteca HTTP)
Establecer y verificar las expectativas en las solicitudes HTTP
Solicitudes de coincidencia basadas en método, URI, encabezados y cuerpo
Matriota inteligente de los mismos URI en diferentes representaciones (también formularios codificados y no codificados)
Matriota inteligente de los mismos encabezados en diferentes representaciones.
Soporte para la prueba :: Unidad
Soporte para RSPEC
Soporte para Minitest
Async :: http :: cliente
Curb (actualmente solo Curb :: Easy)
EM-HTTP-REQUEST
Excón
Httpclient
Gema http (también conocida como http.rb)
httpx
Manticore
Net :: http y otras bibliotecas basadas en net :: http, por ejemplo:
Httparty
Cliente de descanso
Patrón
Typhoeus (actualmente solo Typhoeus :: Hydra)
MRI 2.6
MRI 2.7
MRI 3.0
MRI 3.1
MRI 3.2
MRI 3.3
Jruby
GEM install WebMock
o alternativamente:
# Agregue a su GemFileGroup: Prueba Do GEM "WebMock" Fin
Git clone http://github.com/bblimke/webmock.gitcd webmock instalación de rastrillo
WebMock 2.x ha cambiado un poco desde la versión 1.x. Los cambios se enumeran en ChangeLog.md
Cree un archivo features/support/webmock.rb
con el siguiente contenido:
requiere 'webmock/pepino'
Agregue el siguiente código para test/test_helper
:
requiere 'webmock/minitest'
Agregue el siguiente código a spec/spec_helper
:
Requerir 'WebMock/RSPEC'
Agregue el siguiente código a test/test_helper.rb
requiere 'webMock/test_unit'
También puede usar WebMock fuera de un marco de prueba:
Requerir 'WebMock'InClude WebMock :: APIWEBMOCK.ENABLE!
stub_request (: any, "www.example.com") net :: http.get ("www.example.com", "/") # ===> éxito
stub_request (: post, "www.example.com"). con (Body: "ABC", encabezados: {'content-Length' => 3}) uri = uri.parse ("http://www.example.com/") req = net :: http :: post. New (uri.path) req ['content-longitud'] = 3res = net :: http.start (uri.host, uri.port) do | http | http.request (req, "ABC") final # ===> éxito
stub_request (: post, "www.example.com"). con (Body:/World $/, Headers: {"Content-Type" => /image/.+/}). to_return (cuerpo: "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 # ===> éxito
stub_request (: post, "www.example.com"). con (Body: {Data: {A: '1', B: 'Five'}}) RestClient.Post ('www.example.com', "data [a] = 1 & data [b] = cinco", Content_Type: 'Application/X-WWW-Form-URLENCODED') # ===> SuccessRestClient.Post ('www.example.com', '{"data": {"A": "1", "b": "cinco"}}', content_type: 'Application /Json') # ===> SuccessRestClient.Post ('www.example.com', '<data a = "1" b = "cinco" />', content_type: 'aplicación/xml') # ===> éxito
stub_request (: post, "www.example.com"). con (cuerpo: hash_including ({data: {a: '1', b: 'cinco'}})) RestClient.post ('www.example.com', "data [a] = 1 & data [b] = cinco & x = 1 ",: content_type => 'Application/x-www-form-urlencoded') # ===> éxito
stub_request (: any, "www.example.com"). con (encabezados: {'Header-Name' => 'Header-Value'}) uri = uri.parse ('http://www.example.com/') req = net :: http :: post.new (New ( uri.path) req ['Header-name'] = 'Header-Value'res = net :: http.start (uri.host, uri.port) do | http | http.request (req, 'ABC') End # ===> éxito
stub_request (: get, 'www.example.com'). con (encabezados: {'aceptar' => ['image/jpeg', 'image/png']}) req = net :: http :: get.new ("/") req ['aceptación'] = [' Image/png '] req.add_field (' aceptar ',' image/jpeg ') net :: http.start ("www.example.com") {| http | http.request (req)} # ===> éxito
stub_request (: post, "www.example.com"). Con {| solicitud | request.body == "ABC"} RestClient.Post ('www.example.com', 'ABC') # ===> éxito
stub_request (: get, "www.example.com"). con (básico_auth: ['user', 'pase'])# o# stub_request (: get, "www.example.com").# con (encabezados: {'Autorización' => "Básico #{base64.strict_encode64 ('user: pass'). Chomp}"}) net :: http.start ('www.example.com') do | http | req = net :: http :: get.new ('/') req.basic_auth 'usuario', 'pase' http.request (req) end # ===> éxito
stub_request(:get, "user:[email protected]")
no coincide con una solicitud con las credenciales proporcionadas en el encabezado de autorización.stub_request (: get, "user: [email protected]") RestClient.get ('user: [email protected]') # ===> éxito
stub_request (: any, /example/)net::http.get('www.example.com ','/') # ===> éxito
stub_request (: any, -> (uri) {verdadero})
Uri_template = direccionable :: Template.new "www.example.com/{idh /"stub_request(:any, uri_template) net :: http.get ('www.example.com', '/webMock/') # = = ==> éxito
uri_template = Directable :: Template.new "www.example.com/thing/{idh}.json (?x,y,zhth/eterther*}"stub_request(:any, uri_template) net :: http.get ('www. ejemplo.com ', '/thing/5.json?x=1&y=2&z=3&anyparam=4') # ===> éxito
stub_request (: get, "www.example.com"). With (Query: {"A" => ["B", "C"]}) RestClient.get ("http://www.example.com/ ? a [] = b & a [] = c ") # ===> éxito
stub_request (: get, "www.example.com"). con (Query: Hash_including ({"A" => ["B", "C"]})) RestClient.get ("http://www.example.com/?a[=b&afico=c&x= 1 ") # ===> éxito
stub_request (: get, "www.example.com"). con (consulta: hash_excluding ({"a" => "b"})) restclient.get ("http://www.example.com/?a=b") # ===> faileurestClient.get ("http : //www.example.com/? a = c ") # ===> éxito
stub_request (: any, "www.example.com"). to_return (cuerpo: "abc", estado: 200, encabezados: {'content-longitud' => 3}) net :: http.get ("www.example.com", '/') # ===> " abecedario"
Establezca el tipo de contenido apropiado para parsed_response
de HttParty.
stub_request (: any, "www.example.com").
File.open ('/tmp/respuesta_body.txt', 'w') {| f | F.puts 'ABC'} stub_request (: any, "www.example.com"). to_return (cuerpo: file.new ('/tmp/respuesta_body.txt'), estado: 200) net :: http.get ('www.example.com', '/') # ===> "ABCN"
stub_request (: any, "www.example.com"). to_return_json (cuerpo: {foo: "bar"}) net :: http.get ('www.example.com', '/') # ===> "{" foo ":" bar "}"
stub_request (: any, "www.example.com"). to_return (estado: [500, "error de servidor interno"]) req = net :: http :: get.new ("/") net :: http.start ("www.example.com") {| http | http.request (req)}. Mensaje # ===> "Error de servidor interno"
curl -is
curl -is www.example.com > /tmp/example_curl_-is_output.txt
raw_response_file = file.new ("/tmp/ejemplo_curl_-is_output.txt")
desde el archivo
stub_request (: get, "www.example.com").
o cadena
stub_request (: get, "www.example.com").
stub_request (: any, 'www.example.net'). to_return {| solicitud | {Body: request.body}} RestClient.Post ('www.example.net', 'ABC') # ===> "ABCN"
stub_request (: any, 'www.example.net'). to_return (lambda {| request | {body: request.body}}) restclient.post ('www.example.net', 'ABC') # ===> "ABCN"
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 (cuerpo: lambda {| request | request.body}) RestClient.post ('www.example.net', 'ABC') # ===> "ABCN"
clase Myrackapp def self.call (env) [200, {}, ["Hola"]] endendstub_request (: get, "www.example.com"). To_rack (myRackApp) RestClient.Post ('www.example.com') # ===> "Hola"
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 ("algún error")))
stub_request (: any, 'www.example.net'). to_raise ("algún error")
stub_request (: any, 'www.example.net'). to_timeoUtrestClient.post ('www.example.net', 'ABC') # ===> RestClient :: RequestTimeOut
stub_request (: get, "www.example.com"). to_return ({cuerpo: "ABC"}, {cuerpo: "def"}) net :: http.get ('www.example.com', '/') # ===> "ABCN" net :: http. get ('www.example.com', '/') # ===> "Defn" #After Todas las respuestas se usan, la última respuesta se devolverá InfinIntyNet :: http.get ('www.example.com', ',' /') # ===> "Defn"
to_return()
, to_raise()
o to_timeout
stub_request (: get, "www.example.com"). to_return ({cuerpo: "ABC"}). Entonces. #then () es solo un azúcar sintáctico to_return ({cuerpo: "def"}). Entonces. to_raise (myException) net :: http.get ('www.example.com', '/') # ===> "ABCN" net :: http.get ('www.example.com', '/') # ===> "Defn" net :: http.get ('www.example.com', '/') # ===> myException elevado
stub_request (: get, "www.example.com"). to_return ({cuerpo: "ABC"}). Times (2) .Then. to_return ({cuerpo: "def"}) net :: http.get ('www.example.com', '/') # ===> "ABCN" net :: http.get ('www.example.com ','/') # ===> "ABCN" net :: http.get (' www.example.com ','/') # ===> "DEFN"
stub_get = stub_request (: get, "www.example.com") remove_request_stub (stub_get)
WebMock.how_net_connect! Stub_request (: any, "www.example.com"). To_return (cuerpo: "abc") net :: http.get ('www.example.com', '/') # ===> "ABC" net :: http.get ('www.somthething.com', '/') # ===> /.+somthing.+/webmock.disable_net_connect nenet::http.get('www.something. com ','/') # ===> falla
WebMock.disable_net_connect! (Tampable_localhost: true) net :: http.get ('www.somthing.com', '/') # ===> faileurenet :: http.get ('localhost: 9887', '/')) # ===> permitido. ¿Quizás a Selenium?
Las solicitudes permitidas se pueden especificar de varias maneras.
Con una String
que especifica un nombre de host:
WebMock.disable_net_connect! (Permitir: 'www.example.org') RestClient.get ('www.somhiphing.com', '/') # ===> faileRestClient.get ('www.example.org', '/// ') # ===> permitidoRestClient.get (' www.example.org:8080 ','/') # ===> permitido
Con una String
que especifica un nombre de host y un puerto:
WebMock.disable_net_connect! (Permitir: 'www.example.org:8080')Restclient.get('www.somthing.com', '/') # ===> FailerestClient.get ('www.example.org',,, '/') # ===> FailerestClient.get ('www.example.org:8080', '/') # ===> permitido
Con una Regexp
que coincide con el URI:
WebMock.disable_net_connect! (Permitir: %r {ample.org/foo}) RestClient.get ('www.example.org', '/foo/bar') # ===> permitidoRestClient.get ('sample.org' , '/foo') # ===> permitidoRestClient.get ('sample.org', '/bar') # ===> falla
Con un objeto que responde a #call
, recibiendo un objeto URI
y devolviendo un booleano:
Denylist = ['Google.com', 'Facebook.com', 'Apple.com'] permitido_sites = lambda {| uri | denylist.none? {| sitio | Uri.host.include? (Sitio)}} WebMock.disable_net_connect! (Permitir: permitido_sites) RestClient.get ('www.example.org', '/') # ===> permitidoRestClient.get ('www.facebook. com ','/') # ===> faileRestClient.get (' apple.com ','/') # ===> falla
Con una Array
de cualquiera de los anteriores:
WebMock.disable_net_connect! (Permitir: [ lambda {| uri | uri.host.length % 2 == 0}, /ample.org/, 'bbc.co.uk',]) RestClient.get ('www.example.org', '/') # ===> permitidoRestClient.get ('bbc.co.uk', '/') # == => PermitidoRestClient.get ('bbc.com', '/') # ===> permitidoRestClient.get ('www.bbc.com', '/') # ===> falla
El protocolo HTTP tiene 3 pasos: conectar, solicitud y respuesta (o 4 con cierre). La mayoría de las bibliotecas de clientes Ruby HTTP tratan Connect como parte del paso de solicitud, con la excepción de Net::HTTP
, que permite abrir la conexión al servidor por separado a la solicitud, utilizando Net::HTTP.start
.
La API de WebMock también fue diseñada con Connect como parte del paso de solicitud, y solo permite solicitud de solicitudes, no conexiones. Cuando se llama Net::HTTP.start
, WebMock aún no sabe si una solicitud se quita o no. WebMock, por defecto, retrasa una conexión hasta que se invoca la solicitud, por lo que cuando no hay solicitud, Net::HTTP.start
no hace nada. ¡Esto significa que WebMock rompe el comportamiento NET :: HTTP de forma predeterminada!
Para solucionar este problema, WebMock ofrece :net_http_connect_on_start
, que se puede pasar a WebMock.allow_net_connect!
y WebMock.disable_net_connect!
Métodos, es decir,
WebMock.how_net_connect! (Net_http_connect_on_start: true)
Esto obliga al adaptador WebMock Net :: HTTP para conectarse siempre en Net::HTTP.start
. Al momento de hacer la conexión, no hay información sobre la solicitud o la URL todavía, por lo tanto, WebMock no puede decidir si eliminar una solicitud o no y todas las conexiones están permitidas. Para habilitar las conexiones solo para un dominio específico (por ejemplo, su servidor de prueba) use:
WebMock.how_net_connect! (Net_http_connect_on_start: "www.example.com")
Requerir '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-longitud'] = 3res = net :: http.start (uri.host, uri.port) do | http | http.request (req, 'ABC') endassert_requested: post, "http://www.example.com", encabezados: {'content-length' => 3}, cuerpo: "ABC", Times: 1 # ===> STARSASSERT_NOT_REQUESTES: "http://www.somthing.com" # ===> STARSASSERT_REQUESTEST (: POST, "http://www.example.com", Times: 1) {| req | req.body == "ABC"}
WebMock.how_net_connect! Net :: http.get ('www.example.com', '/') # ===> stactorSassert_requested: get, "http://www.example.com" # ===> éxito
stub_get = stub_request (: get, "www.example.com") stub_post = stub_request (: post, "www.example.com") net :: http.get ('www.example.com', '/') Agered_Rquested (stub_get) ASSERT_NOT_REQUESTED (stub_post)
WebMock
Este estilo se toma prestado de FakeWeb-Matcher
Requerir 'WebMock/RSpec'Expect (WebMock) .To Have_Requested (: Get, "www.example.com"). con (Body: "ABC", encabezados: {'content-longitud' => 3}). TwiceExpect (webMock) .not_to have_requested (: get, "www.somthing.com") esperar (webMock). a have_requested (::::::: Publicar, "www.example.com"). con {| req | req.body == "ABC"}# Tenga en cuenta que el bloque con `do ... end` en lugar de corchetes no funcionará!# ¿Por qué? Vea este comentario https://github.com/bblimke/webmock/issues/174#issuecomment-34908908expect(webmock).to have_requested (: get, "www.example.com"). con (consulta: {"a" => ["b", "c"]}) esperar (webMock) .to have_requested (: get, "www.example.com"). con (consulta: hash_including ({"a" => ["b", "c"]})) esperar (webMock) .To have_requested (: get, "www.example.com"). con (cuerpo: {"a" => ["b", "c"]}, encabezados: {'content-type' => 'application/json'})
a_request
Espere (a_request (: post, "www.example.com"). con (cuerpo: "ABC", encabezados: {'content-longitud' => 3})). a tener_been_made.onceExpect (a_request (: post, "www.somthing.com")). a tener_been_made.times (3) esperar (a_request (: post, "www.somthing.com"). To Have_been_made.at_Least_onceexpect (a_request (: post, "www.somthing.com")). a tener_been_made.at_least_times (3) esperar (a_request (: post, "www.somthething.com")). a tener_been_made.at_most_twiceExpect (a_request (: post, "www.somthing.com")). To Have_been_made.at_most_Times (3 (3 ) esperar (a_request (: any, "www.example.com")). Not_to have_been_madeexpect (a_request (: post, "www.example.com"). Con {| req | req.body == "ABC"}) . a tener_been_madeExpect (a_request (: get, "www.example.com"). With (Query: {"A" => ["B", "C"]})). a tener_been_madeExpect (a_request (: get, "www.example.com"). con (consulta: hash_including ({"a" => ["b", "c"]}))). to have_been_madeExpect (a_request (: post, "www.example.com"). con (cuerpo: {"a" => ["b", "c"]}, encabezados: {'content-type' => 'application/json'})). To_been_made
stub = stub_request (: get, "www.example.com")# ... hacer solicitudes ... esperar (stub) .to have_been_requested
Si desea restablecer todos los trozos e historias actuales de las solicitudes, use WebMock.reset!
stub_request (: any, "www.example.com") net :: http.get ('www.example.com', '/') # ===> Succeswebmock.reset! net :: http.get ('www .example.com ','/') # ===> failureassert_not_requested: get, "www.example.com" # ===> éxito
Si desea restablecer solo los contadores de las solicitudes ejecutadas, use 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('wwww.example2.com', '/')expect(stub) )
# Disable WebMock (todos los adaptadores) WebMock.disable!# Disable WebMock para todos los LIBS excepto net :: httpwebmock.disable! (Excepto: [: net_http])# habilitar webMock (todos los adaptadores) webmock.enable!# Enable webmock para todos los libios para todas las libras Excepto PatronWebMock.enable! (Excepto: [: Patrón])
Una solicitud ejecutada coincide con la solicitud aún si pasa los siguientes criterios:
Cuando la solicitud, URI coincide con la cadena de URI de solicitud, el patrón regexp o la plantilla URI RFC 6570
Y el método de solicitud es el mismo que el método de solicitud retirada o el método de solicitud retirada es: cualquier
Y el cuerpo de solicitud es lo mismo que el cuerpo de solicitud retirada o el cuerpo de solicitud retirada no se especifica
Y los encabezados de solicitud coinciden con los encabezados de solicitud retirados, o los encabezados de solicitud retirados coinciden con un subconjunto de encabezados de solicitud, o no se especifican encabezados de solicitud retirados
Y no se proporcionan coincidencias de solicitud proporcionadas en bloque o bloqueo
Siempre el último stub declarado que coincide con la solicitud se aplicará es decir:
stub_request (: get, "www.example.com"). to_return (cuerpo: "abc") stub_request (: get, "www.example.com"). to_return (cuerpo: "def") net :: http.get ('www.example.com', '/') # ====> "def"
WebMock coincidirá con todas las representaciones diferentes del mismo URI.
Es decir, todas las siguientes representaciones del URI son iguales:
"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/ "
Los siguientes URI con UserInfo también son iguales para WebMock
"A B: [email protected]" "A B: [email protected]/" "A b: [email protected]: 80" "A b: [email protected]: 80/" "http: // a b: [email protected]" "http: // a b: [email protected]/" "http: // a b: [email protected]: 80" "http : // a b: [email protected]: 80/"" A%20b: [email protected] "" A%20b: [email protected]/"" A%20b: pass@ www.example.com:80"cular%20b:[email protected]:80/""http://a%20b:[email protected]"http://a%20b: [email protected]/ "" http: // a%20b: [email protected]: 80 "" http: // a%20b: [email protected]: 80/"
o estos
"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 = mi param & b = c "" www.example.com:80/my%20path/?a=my%20param&b=c "" http://www.example.com/my ruta/? A = My Param & B = B = c "" http://www.example.com/my%20path/?a=my%20param&b=c "" http://www.example.com:80/my ruta/? A = mi param & b = c " "http://www.example.com:80/my%20path/?a=my%20param&b=c"
Si proporciona regexp para que coincida con URI, WebMock intentará igualarlo con cada forma válida de la misma URL.
Es decir /my path/
coincidirá con www.example.com/my%20path
porque es equivalente a www.example.com/my path
Si utiliza la plantilla :: para coincidir, entonces WebMock aplazará las reglas coincidentes con direccionable, que cumple con RFC 6570.
Si utiliza alguno de los métodos webmock para coincidir los parámetros de consulta, entonces se usará direccionable para que coincida con el URI base y WebMock coincidirá con los parámetros de consulta. Si no lo hace, entonces WebMock permitirá que se pueda hacer coincidir con el URI completo.
WebMock coincidirá con los encabezados de solicitud con los encabezados de solicitud retirados en las siguientes situaciones:
La solicitud alredada tiene encabezados especificados y los encabezados de solicitud son los mismos que los encabezados retirados
es decir, los encabezados a Stubbed: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
La solicitud retirada tiene encabezados especificados y los encabezados de solicitud retirados son un subconjunto de encabezados de solicitud
es decir, encabezados Stubbed: { 'Header1' => 'Value1' }
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
La solicitud retirada no tiene encabezados
es decir, encabezados retirados: nil
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
WebMock normaliza los encabezados y trata todas las formas de los mismos encabezados que igual: es decir, los siguientes dos conjuntos de encabezados son iguales:
{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }
{ header1: "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }
Para grabar las interacciones HTTP reales de su aplicación y reproducirlas más tarde en las pruebas puede usar VCR con WebMock.
WebMock.After_Request do | request_signature, respuesta | se puso "la solicitud #{request_signature} se realizó y #{Respuesta} se devolvió" Fin
WebMock.After_Request (excepto: [: Patron], Real_requests_only: true) do | req_signature, respuesta | se puso "la solicitud #{req_signature} se realizó y #{Respuesta} se devolvió" Fin
Envíelos aquí http://github.com/bblimke/webmock/issues
Puede contribuir mediante problemas de triado que pueden incluir reproducir informes de errores o solicitar información vital, como números de versión o instrucciones de reproducción. Si desea comenzar a triando problemas, una manera fácil de comenzar es suscribirse a WebMock en CodeRAGE.
Si tiene alguna sugerencia sobre cómo mejorar WebMock, envíe un correo electrónico a los grupos de listas de correo.google.com/group/webmock-users
Estoy particularmente interesado en cómo se podría mejorar el DSL.
Para trabajar en WebMock, primero necesita bifurcarse y clonar el repositorio. Haga cualquier trabajo en una sucursal dedicada y Rebase contra Master antes de enviar una solicitud de extracción.
¡Las líneas iniciales de este proyecto se escribieron durante el nuevo Día de Hack de Bamboo gracias a mis compañeros Bambinos por todas las grandes sugerencias!
Las personas que presentaron parches y nuevas características o mejoras sugeridas. Muchas gracias a estas personas:
Ben Pickles
Mark Evans
Ivan Vega
Piotr Usewicz
Nick Plante
Nick Quaranto
Diego E. "Flameyes" Pettenò
Niels Meersschaert
Mack Earnhardt
Arvicco
Sergio Gil
Jeffrey Jones
Tekin Suleyman
Tom Ward
Nadim bitar
Myron Marston
Sam Phillips
José Angel Cortinas
Maíz
Steve Tooke
Nathaniel Bibller
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
Shterenzon romano
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
Aindustrias
Eric Oestrich
erwanlr
Ben Bleything
Jon Leighton
Ryan Schlesinger
Julien Boyer
Kevin Glowacz
Hans Hasselberg
Andrew Francia
Jonathan Hyman
Rex Feng
Manta
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 fuerte
Tamir Duberstein
Stefano uliari
Alex Stupakov
Karen Wang
Matt Burke
Jon Rowe
Aleksey V. Zapparov
Praveen arrimbrathodiyil
Bo jeans
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 tu
Simon Russell
Steve Mitchell
Mattias Putman
Zachary Anker
Emmanuel Sambo
Ramón 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
José Luis Honorato
Aaron Kromer
Pavel Jurašek
Jake vale
Gabe Martin-Dempesia
Michael Grosser
Aleksei Maridashvili
Ville lautanala
Koichi Ito
Cárcel jordán
Tarmo tänav
Joe Marty
Chris Thomson
Vít ondruch
George Ulmer
Christof Koenig
Chung-yi chi
Olexandr hoshylyk
Janko Marohnić
Pat Allan
Canción de Rick
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
Panadero gris
Prontokhen owyong
Pavel Valena
Adam Sokolnicki
Jeff Felchner
Eike enviar
Claudio Poli
Csaba apagyi
Frederick Cheung
Fábio D. Batista
Andriy Yanko
yagi
Rafael França
George Claghorn
Alex Junger
Orien Madgwick
Andrei Storov
Marco Costa
Ryan Davis
Brandur
Samuel Williams
Patrik Ragnarsson
Alex Cooman
Vesa laakso
John Hawthorn
GUPPY0356
Thilo Rusche
Andrew Stuntz
Lucas Uyezu
Bruno Sutic
Ryan Kerr
Adam Harwood
Ben Koshy
Jesse Bowes
Marek Kasztelnik
CE07C3
Jiang Jiang
Oleksiy kovyrin
Matt Larraz
Tony Schneider
Niklas Hösl
Johanna Hartmann
Alex Vondrak
Will Storey
Eduardo Hernández
ojab
Giorgio Gambino
Timmitry
Michael Fairley
Ray Zane
Ir a suyoshi
Cedric Sohrauer
Akira Matsuda
Mark spangler
Henrik nyh
Yoann Lecuyer
Lucas Arnaud
Marc Rohloff
tinta
Yuki Inoue
Weaver de Brandon
Josh Nichols
Ricardo Trindade
Earlopain
James Brown
Kazuhiro nishiyama
Étienne Barrié
Matt Brown
Victor Maslov
Gio Lodi
Ryan Brooks
Jacob Frautschi
Christian Schmidt
Rodrigo Argumedo
Para una lista completa de contribuyentes, puede visitar la página de contribuyentes.
¡Gracias FakeWeb! Esta biblioteca se inspiró en FakeWeb. Importé algunas soluciones de ese proyecto a WebMock. También copié algún código, es decir, adaptador HTTP. La arquitectura FakeWeb desafortunadamente no me permitió extenderla fácilmente con las características que necesitaba. También preferí algunas cosas para que funcionen de manera diferente, es decir, solicitar precedencia.
Copyright (c) 2009-2010 Bartosz Blimke. Vea la licencia para más detalles.