Biblioteca para Stubbing e estabelecendo expectativas nas solicitações HTTP no Ruby.
Solicitações HTTP de Stubbing no nível LIB do cliente baixo HTTP (sem necessidade de alterar os testes quando você alterar a biblioteca HTTP)
Definir e verificar as expectativas em solicitações HTTP
Solicitações correspondentes com base no método, URI, cabeçalhos e corpo
Combinação inteligente dos mesmos URIs em diferentes representações (também formulários codificados e não codificados)
Combinação inteligente dos mesmos cabeçalhos em diferentes representações.
Suporte para teste :: unidade
Suporte ao RSPEC
Apoio ao MiniTest
Assíncrono :: http :: cliente
Meio -fio (atualmente apenas meio -fio :: fácil)
EM-HTTP-REQUEST
Excon
HttpClient
HTTP GEM (também conhecido como http.rb)
httpx
Manticore
Net :: http e outras bibliotecas baseadas em net :: http, por exemplo:
Httparty
Cliente de repouso
Patrono
Typhoeus (atualmente apenas Typhoeus :: Hydra)
RM 2.6
RM 2.7
RM 3.0
RM 3.1
RM 3.2
RM 3.3
Jruby
Gem Instale Webmock
ou alternativamente:
# Adicionar ao seu GemFileGroup: teste Gem "Webmock" final
Git Clone http://github.com/bblimke/webmock.gitcd webmock Instalação de ancinho
Webmock 2.x mudou um pouco desde a versão 1.x. As alterações estão listadas no Changelog.md
Crie um arquivo features/support/webmock.rb
com os seguintes conteúdos:
requer 'webmock/pepino'
Adicione o código a seguir para test/test_helper
:
requer 'webmock/minitest'
Adicione o seguinte código a spec/spec_helper
:
requer 'webmock/rspec'
Adicione o seguinte código para test/test_helper.rb
requer 'webmock/test_unit'
Você também pode usar o webmock fora de uma estrutura de teste:
requer 'webmock'include webmock :: apiwebmock.enable!
Stub_Request (: qualquer, "www.example.com") net :: http.get ("www.example.com", "/") # ===> Sucesso
stub_request (: post, "www.example.com"). com (corpo: "abc", cabeçalhos: {'content-comprimento' => 3}) uri = uri.parse ("http://www.example.com/") req = net :: http :: post. novo (URI.Path) req ['content-length'] = 3res = net :: http.start (uri.host, uri.port) do | http | http.request (req, "abc") final # ===> Sucesso
stub_request (: post, "www.example.com"). com (corpo:/mundial $/, cabeçalhos: {"content-type" => /image/.+/}). to_return (corpo: "abc") uri = uri.parse ('http://www.example.com/') req = net :: http :: post.new (uri.path) req ['content-type' ] = 'imagem/png'res = net :: http.start (uri.host, uri.port) do | http | http.request (req, 'hello world') final # ===> Sucesso
stub_request (: post, "www.example.com"). com (corpo: {data: {a: '1', b: 'cinco'}}) restlient.post ('www.example.com', "dados [a] = 1 & dados [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: 'Application/Xml') # ===> Sucesso
stub_request (: post, "www.example.com"). com (corpo: hash_including ({data: {a: '1', b: 'cinco'}})) RestClient.post ('www.example.com', "dados [a] = 1 & dados [b] = cinco & x = 1 ",: Content_type => 'Application/X-Www-Form-Urlencoded') # ===> Sucesso
stub_request (: qualquer, "www.example.com"). com (cabeçalhos: {'nomes de cabeçalho' => 'Cabeçalho-valor'}) uri = uri.parse ('http://www.example.com/') req = net :: http :: post.new ( uri.path) req ['nomes de cabeçalho'] = 'cabeçalho-value'res = net :: http.start (uri.host, uri.port) do | http | http.request (req, 'abc') final # ===> Sucesso
stub_request (: get, 'www.example.com'). com (cabeçalhos: {'Acep' => ['image/jpeg', 'image/png']}) req = net :: http :: get.new ("/") req ['aceite'] = [' Image/png '] req.add_field (' Aceitar ',' image/jpeg ') net :: http.start ("www.example.com") {| http | http.request (req)} # ===> Sucesso
stub_request (: post, "www.example.com"). Com {| request | request.body == "abc"} RestClient.post ('www.example.com', 'abc') # ===> Sucesso
stub_request (: get, "www.example.com"). Com (Basic_auth: ['Usuário', 'pass'])# ou# stub_request (: get, "www.example.com").# com (cabeçalhos: {'Autorização' => "Basic #{BASE64.STRICT_ENCODE64 ('Usuário: Pass'). Chomp}"}) net :: http.start ('www.example.com') do | http | req = net :: http :: get.new ('/') req.basic_auth 'user', 'passa' http.request (req) final # ===> Sucesso
stub_request(:get, "user:[email protected]")
não corresponde a uma solicitação com credenciais fornecidas no cabeçalho da autorização.stub_request (: get, "user: [email protected]") RESTCLIENT.GET ('Usuário: [email protected]') # ===> Sucesso
stub_request (: qualquer, /example/)net::http.get('www.example.com ','/') # ===> Sucesso
stub_request (: qualquer, -> (uri) {true})
uri_template = endereçável :: template.new "www.example.com/ {iDage {{{{ ==> Sucesso
uri_template = Endereço :: template.new "www.example.com/thing/ {iDage.json (?x,y.z} {&other* }"stub_request(:any, uri_template) net :: http.get ('www. exemplo.com ', '/thing/5.json?x=1&y=2&z=3&anyparam=4') # ===> Sucesso
stub_request (: get, "www.example.com"). Com (Query: {"A" => ["B", "C"]}) RestClient.get ("http://www.example.com/ ? a [] = B & a [] = C ") # ===> Sucesso
stub_request (: get, "www.example.com"). com (consulta: hash_including ({"a" => ["b", "c"]})) RestClient.get ("http://www.example.com/?a: ]=b&a[-cha 1 ") # ===> Sucesso
stub_request (: get, "www.example.com"). com (Query: hash_excluding ({"a" => "b"})) RestClient.get ("http://www.example.com/?a=b") # ===> failurerestclient.get ("http : //www.example.com/? A = c ") # ===> Sucesso
stub_request (: qualquer, "www.example.com"). to_return (corpo: "abc", status: 200, cabeçalhos: {'content-length' => 3}) net :: http.get ("www.example.com", '/') # ===> " abc"
Defina o tipo de conteúdo apropriado para parsed_response
de HttParty.
stub_request (: qualquer, "www.example.com"). To_return Body: '{}', cabeçalhos: {content_type: 'Application/json'}
File.open ('/tmp/resposta_body.txt', 'w') {| f | f.puts 'abc'} stub_request (: qualquer, "www.example.com"). to_return (corpo: file.new ('/tmp/Response_body.txt'), status: 200) net :: http.get ('www.example.com', '/') # ===> "abcn"
stub_request (: qualquer, "www.example.com"). to_return_json (corpo: {foo: "bar"}) net :: http.get ('www.example.com', '/') # ===> "{" foo ":" bar "}"
stub_request (: qualquer, "www.example.com"). to_return (status: [500, "Erro do servidor interno"]) req = net :: http :: get.new ("/") net :: http.start ("www.example.com") {| http | http.request (req)}. Mensagem # ===> "Erro do servidor interno"
curl -is
curl -is www.example.com > /tmp/example_curl_-is_output.txt
RAW_RESPONSEIRO_FILE = FILE.NEW ("/TMP/EXEMPLE_CURL_-IS_OUTPUT.TXT")
do arquivo
stub_request (: get, "www.example.com"). To_return (raw_response_file)
ou string
stub_request (: get, "www.example.com"). To_return (raw_rosponse_file.read)
stub_request (: qualquer, 'www.example.net'). to_return {| request | {Body: request.body}} RestClient.post ('www.example.net', 'abc') # ===> "abcn"
stub_request (: qualquer, 'www.example.net'). to_return (lambda {| request | {body: request.body}}) restlient.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 (: qualquer, 'www.example.net'). to_return (corpo: lambda {| request | request.body}) restlient.post ('www.example.net', 'abc') # ===> "abcn"
Classe MyRackapp def self.call (Env) [200, {}, ["hello"]] endendstub_request (: get, "www.example.com"). to_rack (myrackapp) RestClient.post ('www.example.com') # ===> "Hello"
stub_request (: qualquer, 'www.example.net'). to_raise (standarderror) restlient.post ('www.example.net', 'abc') # ===> StandardError
stub_request (: qualquer, 'www.example.net'). to_raise (standarderror.new ("algum erro"))
stub_request (: qualquer, 'www.example.net'). to_raise ("algum erro")
stub_request (: qualquer, 'www.example.net'). to_timeoutrestcient.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', '/') # ===> "abcn" net :: http. get ('www.example.com', '/') # ===> "defn" #after Todas as respostas são usadas, a última resposta será retornada infinitelynet :: http.get ('www.example.com', ' /') # ===> "defn"
to_return()
, to_raise()
ou to_timeout
stub_request (: get, "www.example.com"). to_return ({body: "abc"}). Então. #then () é apenas um açúcar sintático to_return ({body: "def"}). Então. 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 ({body: "abc"}). vezes (2). to_return ({body: "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") REMOVER_REQUEST_STUB (STUB_GET)
Webmock.allow_net_connect! Stub_request (: qualquer, "www.example.com"). To_return (corpo: "abc") net :: http.get ('www.example.com', '/') # ===> "ABC" net :: http.get ('www.something.com', '/') # ===> /.+something.+/webmock.disable_net_connect!Net::http.get('ww.something. com ','/') # ===> falha
Webmock.disable_net_connect! (Allow_localhost: true) net :: http.get ('www.something.com', '/') # ===> FailureNet :: http.get ('localhost: 9887', '/') # ===> permitido. Talvez para o selênio?
As solicitações permitidas podem ser especificadas de várias maneiras.
Com uma String
especificando um nome de host:
Webmock.disable_net_connect! (Permitir: 'www.example.org') RestClient.get ('www.something.com', '/') # ===> FailurerestClient.get ('www.example.org', '/ ') # ===> Permisistrestclient.get (' www.example.org:8080 ','/') # ===> permitido
Com uma String
especificando um nome de host e uma porta:
Webmock.disable_net_connect! (Aguarde: 'www.example.org:8080')restclient.get('www.something.com', '/') # ===> failurerestclient.get ('www.example.org', '/') # ===> FailurerestClient.get ('www.example.org:8080', '/') # ===> permitido
Com um Regexp
que corresponde ao URI:
Webmock.disable_net_connect! (Permitir: %r {ample.org/foo}) RestClient.get ('www.example.org', '/foo/bar') # ===> permitir -seRestclient.get ('sample.org' , '/foo') # ===> permithrestclient.get ('sample.org', '/bar') # ===> falha
Com um objeto que responde a #call
, recebendo um objeto URI
e retornando um booleano:
DeNYLIST = ['google.com', 'facebook.com', 'Apple.com'] allowed_sites = lambda {| uri | DeNylist.None? {| Site | uri.host.include? (site)}} webmock.disable_net_connect! (permitir: allowed_sites) RestClient.get ('www.example.org', '/') # ===> allowrestclient.get ('www.facebook. com ','/') # ===> FailurerestClient.get (' Apple.com ','/') # ===> Falha
Com uma Array
de qualquer um dos itens acima:
Webmock.disable_net_connect! (Permitir: [ lambda {| uri | uri.host.length % 2 == 0}, /ple.org/, 'bbc.co.uk',]) RestClient.get ('www.example.org', '/') # ===> permithrestclient.get ('bbc.co.uk', '/') # == => Permisistrestclient.get ('bbc.com', '/') # ===> permithrestclient.get ('www.bbc.com', '/') # ===> falha
O protocolo HTTP possui 3 etapas: conectar, solicitar e resposta (ou 4 com fechar). A maioria das bibliotecas de clientes Ruby HTTP tratam Connect como parte da etapa de solicitação, com exceção do Net::HTTP
, que permite a abertura da conexão com o servidor separadamente à solicitação, usando Net::HTTP.start
.
A API do WebMock também foi projetada com o Connect como parte da etapa de solicitação e só permite solicitações de mascas, não conexões. Quando Net::HTTP.start
é chamado, o WebMock ainda não sabe se uma solicitação é morta ou não. Por padrão, o WebMock atrasa uma conexão até que a solicitação seja invocada; portanto, quando não houver solicitação, Net::HTTP.start
não faz nada. Isso significa que o webmock quebra o comportamento da rede :: HTTP por padrão!
Para alternar esse problema, o WebMock oferece :net_http_connect_on_start
, que pode ser passada para WebMock.allow_net_connect!
e WebMock.disable_net_connect!
Métodos, ou seja
Webmock.allow_net_connect! (Net_http_connect_on_start: true)
Isso força o adaptador WebMock Net :: HTTP a se conectar sempre na Net::HTTP.start
. No momento da conexão, ainda não há informações sobre a solicitação ou URL, portanto, o WebMock não pode decidir se deve formar uma solicitação ou não e todas as conexões são permitidas. Para ativar as conexões apenas para um domínio específico (por exemplo, seu servidor de teste), use:
Webmock.allow_net_connect! (Net_http_connect_on_start: "www.example.com")
requer 'webmock/test_unit'stub_request (: qualquer, "www.example.com") uri = uri.parse (' http://www.example.com/ ') req = net :: http :: post.new ( uri.path) req ['content-length'] = 3res = net :: http.start (uri.host, uri.port) do | http | http.request (req, 'abc') endassert_requested: post, "http://www.example.com", Cabeçalhos: {'content-comprimento' => 3}, corpo: "abc", Times: 1 # ===> successassest_not_requested: get, "http://www.something.com" # ===> successassest_requested (: post, "http://www.example.com", Tempos: 1) {| req | req.body == "abc"}
Webmock.allow_net_connect! Net :: http.get ('www.example.com', '/') # ===> successassest_request: get, "http://www.example.com" # ===> Sucesso
stub_get = stub_request (: get, "www.example.com") stub_post = stub_request (: post, "www.example.com") net :: http.get ('www.example.com', '/') Assert_Request (stub_get) assert_not_requested (stub_post)
WebMock
Este estilo é emprestado do FakeWeb-Matcher
requer 'webmock/rspec'extep (webmock). para ter_requestado (: get, "www.example.com"). com (corpo: "abc", cabeçalhos: {'content-comprimento' => 3}). Tweexpect (webmock) .not_to hese_requested (: get, "www.something.com") post, "www.example.com"). com {| req | req.body == "ABC"}# Observe que o bloco com `do ... end` em vez de colchetes encaracolados não funcionará!# Por quê? Consulte este comentário https://github.com/bblimke/webmock/issues/174#issuecomment-34908908pect(webmock).to Have_requested (: Get, "www.example.com"). com (consulta: {"a" => ["b", "c"]}) espera (webmock). para ter_requestado (: get, "www.example.com"). com (Query: hash_including ({"a" => ["b", "c"]})) espera (webmock). para ter_requestado (: get, "www.example.com"). com (corpo: {"a" => ["b", "c"]}, cabeçalhos: {'content-type' => 'Application/json'})
a_request
Espere (a_request (: Post, "www.example.com"). com (corpo: "abc", cabeçalhos: {'content-comprimento' => 3})). para ter_been_made.onceExpect (a_request (: post, "www.something.com")). (: Post, "www.something.com")). Para ter_been_made.at_least_times (3) esperar (a_request (: post, "www.something.com")). ) Espere (a_REQUEST (: qualquer, "www.example.com")). Not_to Have_been_madeExpect (a_request (: post, "www.example.com"). Com {| req | req.body == "ABC"}) . para ter_been_madeexpect (a_request (: get, "www.example.com"). com (consulta: {"a" => ["b", "c"]})). para ter_been_madeexpect (a_request (: get, "www.example.com"). com (consulta: hash_including ({"a" => ["b", "c"]}))). TENHA_BEEN_MADEEXPPECT (a_Request (: post, "www.example.com"). com (corpo: {"a" => ["b", "c"]}, cabeçalhos: {'content-type' => 'Application/json'})).
stub = stub_request (: get, "www.example.com")# ... faça solicitações ... Espere (stub). para ter_been_requested
Se você deseja redefinir todos os stubs atuais e histórico de solicitações, use WebMock.reset!
stub_request (: qualquer, "www.example.com") net :: http.get ('www.example.com', '/') # ===> successwebmock.reset! net :: http.get ('www .example.com ','/') # ===> Failureassert_not_requested: get, "www.example.com" # ===> Sucesso
Se você deseja redefinir apenas os contadores das solicitações executadas, 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('www.example2.com', '/')expect(stub).to ter_been_request.times (2) Espere (stub2). para ter_been_requested.times (1) webmock.reset_executed_requests!
# Desative o webmock (todos os adaptadores) webmock.disable!# Desative o webmock para todas as libs, exceto net :: httpwebmock.disable! (Exceto: [: net_http])# Ativar webmock (todos os adaptadores) webmock.enable! Exceto Patrowebmock.enable! (Exceto: [: patrono])
Uma solicitação executada corresponde à solicitação forçada se ela passar os seguintes critérios:
Quando a solicitação URI corresponde a String de Uri, padrão de regexp ou modelo regexp ou RFC 6570 URI
E o método de solicitação é o mesmo que o método de solicitação Stubbed ou o método de solicitação de manchas é: qualquer
E o corpo de solicitação é o mesmo que o corpo de solicitação ou o corpo de solicitação de retubbed não é especificado
E os cabeçalhos de solicitação correspondem aos cabeçalhos de solicitação Stubbed ou aos cabeçalhos de solicitação que correspondem a um subconjunto de cabeçalhos de solicitação ou cabeçalhos de solicitação de tumulto não são especificados
E solicitar correspondências fornecidas em bloco ou bloco não é fornecido
Sempre o último stub declarado que corresponde à solicitação será aplicado, ou seja:
stub_request (: get, "www.example.com"). to_return (corpo: "abc") stub_request (: get, "www.example.com"). to_return (body: "def") net :: http.get " ('www.example.com', '/') # ====> "def"
O WebMock corresponderá a todas as diferentes representações do mesmo URI.
Ou seja, todas as seguintes representações do URI são iguais:
"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/ "
Os seguintes URIs com UserInfo também são iguais para o webmock
"A B: [email protected]" "A B: [email protected]/" "A B: [email protected]: 80" "A B: [email protected]: 80/" "http: // b: [email protected]" "http: // b: [email protected]/" "http: // b: [email protected]: 80" "http : // a b: [email protected]: 80/"" a%20b: [email protected] "" A%20B: [email protected]/"" A%20b: passa@ www.example.com:80""a%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/"
ou estes
"www.example.com/my Path/? A = meu param & b = c" "www.example.com/my%20path/?a=my%20Param&b=c" "www.example.com:80/my Path/ ? a = meu param & b = c "" www.example.com:80/my%20path/?a=my%20Param&b=c "" http://www.example.com/my Path/? A = meu param & b = C "" http://www.example.com/my%20path/?a=my%20Param&b=c "" http://www.example.com:80/my Path/? A = meu param & b = c " "http://www.example.com:80/my%20path/?a=my%20Param&b=c"
Se você fornecer o Regexp para corresponder ao URI, o WebMock tentará correspondê -lo a cada forma válida do mesmo URL.
Ou seja /my path/
combinará www.example.com/my%20path
porque é equivalente a www.example.com/my path
Se você usar o modelo endereçável :: para corresponder, o WebMock adiará as regras correspondentes para endereçáveis, que cumprem a RFC 6570.
Se você usar algum dos métodos do WebMock para corresponder parâmetros de consulta, o endereçável será usado para corresponder ao URI e WebMock base corresponderá aos parâmetros de consulta. Caso contrário, o WebMock permitirá que o endereçável corresponda ao URI completo.
O WebMock corresponderá aos cabeçalhos de solicitação contra os cabeçalhos de solicitação de manchas nas seguintes situações:
A solicitação de manchas tem cabeçalhos especificados e os cabeçalhos de solicitação são os mesmos que os cabeçalhos manchados
ou seja, cabeçalhos tobados: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
A solicitação de manchas tem cabeçalhos especificados e os cabeçalhos de solicitação são um subconjunto de cabeçalhos de solicitação
ou seja, os cabeçalhos tocados: { 'Header1' => 'Value1' }
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
Solicitação de manchas não tem cabeçalhos
ou seja, cabeçalhos tocados: nil
, solicitado: { 'Header1' => 'Value1', 'Header2' => 'Value2' }
O webmock normaliza cabeçalhos e trata todas as formas dos mesmos cabeçalhos que iguais: ou seja, os dois conjuntos de cabeçalhos a seguir são iguais:
{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }
{ header1: "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }
Para registrar as interações reais HTTP do seu aplicativo e reproduzi -las posteriormente nos testes, você pode usar o videocassete com o webmock.
Webmock.after_request do | request_signature, resposta | Puts "Solicitação #{request_signature} foi feita e #{Response} foi retornado" Fim
Webmock.after_request (exceto: [: patrono], real_requests_only: true) do | req_signature, resposta | Puts "Solicitação #{req_signature} foi feita e #{Response} foi retornado" Fim
Envie -os aqui http://github.com/bblimke/webmock/issues
Você pode contribuir com problemas de triplo que podem incluir reprodução de relatórios de bug ou solicitação de informações vitais, como números de versão ou instruções de reprodução. Se você deseja iniciar problemas de triplo, uma maneira fácil de começar é se inscrever no WebMock no CodeTreiage.
Se você tiver alguma sugestão sobre como melhorar o webmock, envie um email para os grupos de listas de discussão.google.com/group/webmock-users
Estou particularmente interessado em como a DSL poderia ser melhorada.
Para trabalhar no webmock, você primeiro precisa bifurcar e clonar o repositório. Faça qualquer trabalho em uma filial dedicada e rebase contra o Master antes de enviar uma solicitação de tração.
As linhas iniciais deste projeto foram escritas durante o novo dia de bambu, graças aos meus colegas bambinos por todas as ótimas sugestões!
Pessoas que enviaram patches e novos recursos ou melhorias sugeridas. Muito obrigado a essas pessoas:
Ben Pickles
Mark Evans
Ivan Vega
Piotr usewicz
Nick Plante
Nick Quaranto
Diego E. "Flameeyes" Pettenò
Niels Meerschaert
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
Aindustrias
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 Stuvakov
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
Instone Buzz Jung
Carlos Alonso Pérez
Trorenz
Alexander Simonov
Thorbjørn Hermannse
Mark Lorenz
TJSOUSA
Tasos Stathopoulos
Dan Buettner
Sven Riedel
Mark Lorenz
Dávid Kovács
Fishermand46
Franky Wahl
Chayoung você
Simon Russell
Steve Mitchell
Mattias Putman
Zachary Anker
Emmanuel Sambo
Ramon Tayag
Johannes Schlumberger
Siôn le Roux
Matt Palmer
Zhao Wen
Krzysztof Rygielski
Terra Magne
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-Dempesa
Michael Grosser
Aleksei Maridashvili
Ville Lautanala
Koichi Ito
Jordan Harband
Tarmo Tänav
Joe Marty
Chris Thomson
VIT 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 Brittson
Kenny Ortmann
Redbar0n
Lukas Pokorny
Arkadiy Tetelman
Kazato Sugimoto
Olle Jonsson
Pavel Rosický
Geremia taglialatela
Koichi Sasada
Yusuke endoh
Baker cinza
Soonkhen Owyong
Pavel Valena
Adam Sokolnicki
Jeff Felchner
Eike envia
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
John Hawthorn
GUPPY0356
Thilo Rusche
Andrew Stuntz
Lucas Uyezu
Bruno Sutic
Ryan Kerr
Adam Harwood
Ben Koshy
Jesse Bowes
Marek Kasztelnik
CE07C3
Jun Jiang
Oleksiy Kovyrin
Matt Larraz
Tony Schneider
Niklas Hösl
Johanna Hartmann
Alex Vondrak
Will Storey
Eduardo Hernandez
Ojab
Giorgio Gambino
TIMMITRY
Michael Fairley
Ray Zane
Vá Sueyoshi
Cedric Sohrauer
Akira Matsuda
Mark Spangler
Henrik NYH
Yoann Lecuyer
Lucas Arnaud
Marc Rohloff
Inkstak
Yuki inoue
Brandon Weaver
Josh Nichols
Ricardo Trindade
Earlpain
James Brown
Kazuhiro Nishiyama
Étienne barrié
Matt Brown
Victor Maslov
Gio Lodi
Ryan Brooks
Jacob Frautschi
Christian Schmidt
Rodrigo Argumedo
Para uma lista completa de colaboradores, você pode visitar a página dos colaboradores.
Obrigado FakeWeb! Esta biblioteca foi inspirada pelo FakeWeb. Eu importei algumas soluções desse projeto para o webmock. Também copiei algum código, ou seja, o adaptador HTTP. Infelizmente, a Arquitetura da FakeWeb não me permitiu estendê -la facilmente com os recursos que eu precisava. Eu também preferia algumas coisas para trabalhar de maneira diferente, ou seja, solicitar precedência.
Copyright (C) 2009-2010 Bartosz Blimke. Consulte a licença para obter detalhes.