Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
86
Help us understand the problem. What is going on with this article?
@ogawatti

webmock使ってみた

More than 5 years have passed since last update.

webmockとは

HTTPリクエストをstubするgemです。
Net::HTTPだけでなく、TCPSocketを使った場合もstubしてくれます。

以前、sham_rack使ってみたという記事を書きましたが、
sham_rackはNet::HTTPのstubしかしてくれないのです。
TCPSocketをstubしてくれるgemを探していたところ、このgemに出会いました。

何ができるか

HTTPリクエストをリクエストホストに対して投げる前にフックして、あたかも処理されたようにレスポンスを返すことができる。
つまり、StubやMockのようなことができる。
しかも、Net::HTTPだけでなくTCPSocketも対応してくれる。

=> HTTPClientやExconもstubできることに!

有名なgemなので、いろんな方が記事にされていたりしますが、テスト中のリクエストのstubに利用するケースが多いようです。

使い方

(テストでの使い方は記事にされている方がたくさんいるのでそちらを参照してください)

基本的には、WebMock::APIを該当クラスにincludeすることでstubを登録できるようになります。
しかし、これだけだと、stubを登録しないとエラーになりますので注意してください。

stubを登録せずにリクエストするとエラーになる

require 'webmock'
include WebMock::API
res = Net::HTTP.get("www.example.com", "/")  #=> WebMock::NetConnectNotAllowedError

__END__

具体的には以下のようなエラーメッセージが出力される。

/home/aries/.rvm/gems/ruby-2.1.5@ironna/gems/webmock-1.21.0/lib/webmock/http_lib_adapters/net_http.rb:114:in `request': Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'} (WebMock::NetConnectNotAllowedError)

You can stub this request with the following snippet:

stub_request(:get, "http://www.example.com/").
  with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
  to_return(:status => 200, :body => "", :headers => {})

stub_request (stubするリクエストの登録)

stub_requestで登録する。
第一引数にメソッド名(:anyにすると何でも)、第二引数にホスト名を指定する。

require 'net/http'
require 'webmock'
include WebMock::API

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

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

allow_net_connect! (stub登録したホスト以外へのアクセスは許可する)

require 'webmock'
include WebMock::API

WebMock.allow_net_connect!

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

http = HTTPClient.new
res = http.get "http://www.example.com/"
p res.status  #=> 200
p res.body    #=> "test_ok"

http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status  #=> 200
p res.body    #=> GoogleのトップページのHTML

enable!/disable! (WebMockのon/off切り替え)

この機能が一番使いたかったやつ!!

require 'httpclient'
require 'webmock'
include WebMock::API

## includeしてstub_requestした時点でWebMockは有効になっている

stub_request(:any, "www.google.co.jp").to_return(
 :body => "mock response",
 :status => 200,
 :headers => { 'Content-Length' => 13 }
)
http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status       #=> 200
p res.body[0..30]  #=> "mock response"

WebMock.disable!  #=> 無効化
http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status  #=> 200
p res.body    #=> Googleのトップページ

WebMock.enable!  #=> 有効化
http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status  #=> 200
p res.body    #=> "mock response"

reset! (登録したstubのリセット)

require 'httpclient'

require 'webmock'
include WebMock::API

WebMock.allow_net_connect!
stub_request(:any, "www.google.co.jp").to_return(
 :body => "mock response",
 :status => 200,
 :headers => { 'Content-Length' => 13 }
)
http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status  #=> 200
p res.body    #=> "mock response"

WebMock.reset!  #=> stub_requestで登録したStubがリセットされる
http = HTTPClient.new
res = http.get "http://www.google.co.jp/"
p res.status  #=> 200
p res.body    #=> Googleのトップページ

stub_request().to_rack (rackミドルウェアを登録することもできる)

FbGraphを使った、GraphAPIへの/meリクエストをWebMockでmockしてみた。

require 'fb_graph'
require 'dotenv'
require 'nenv'
require 'webmock'
include WebMock::API

WebMock.allow_net_connect!
Dotenv.load

class MyRackApp
  def call(env)
    [ 500, {}, [ "{}" ] ]
  end
end

class MyMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    if request.path == "/me"
      test_data = { "name" => "Test User" }.to_json
      [ 200, { "Content-Type" => "application/json" }, [ test_data ] ]
    else
      @app.call(env)
    end
  end
end

app = MyRackApp.new
app = MyMiddleware.new(app)
stub_request(:any, /graph\.facebook\.com/).to_rack(app)

user = FbGraph::User.me(Nenv.access_token).fetch
p user.name  #=> "Test User"
86
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ogawatti
jrits
信頼と魅力のある先進のITをもとに、お客様のワークスタイル・イノベーションの実現を目指します。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
86
Help us understand the problem. What is going on with this article?