LoginSignup
43
24

More than 5 years have passed since last update.

Railsで外部リクエストをスタブする

Posted at

Microservices化などでRailsからも外部サービスへリクエストすることが増えてきました。
テストなどで実際に外部サービスへリクエストしてしまうとなにかとね、、
なので、Webmockを使ってスタブしてみましょう。

READMEにも書かれてますが、WebmockはRubyのHTTPライブラリをスタブするだけで、フロントからの外部リクエストをスタブすることができないので注意が必要です:persevere:

フロントからのリクエストをスタブしたい場合は、1日目に @chimame さんが書いてくれてるので参考にしてください:smile:
:eyes: featureスペックでクライアント(JavaScript)側から呼び出すRequestをモックする

この記事のサンプルコード murajun1978/webmock-sample

リクエストをスタブする

Webmockにスタブするリクエストにレスポンスを設定して登録します。

base_stub.rb
require 'bundler'
Bundler.require

require 'webmock'
require 'faraday'
include WebMock::API

WebMock.enable!

client = Faraday.new(url: 'http://www.example.com')

stub_request(:any, "www.example.com").to_return(
  body: 'success!',
  status: 200
)

res = client.get '/'

pp "status: #{res.status}, body: #{res.body}" #=> "status: 200, body: success!"

マッチしたリクエストをスタブする

bodyやqueryなどマッチしたリクエストをスタブに登録します。

matching_stub.rb
require 'bundler'
Bundler.require

require 'webmock'
require 'faraday'
include WebMock::API

WebMock.enable!

client = Faraday.new(url: 'http://www.example.com')

stub_request(:post, "www.example.com").with(
  body: { message: 'Hello' }
).to_return(
  body: 'success!',
  status: 201
)

res = client.post '/', { message: 'Hello' }
pp "status: #{res.status}, body: #{res.body}" #=> "status: 201, body: success!"

外部リクエストを許可する

WebmockはすべてのHttpリクエストをスタブするので、スタブ登録されていないリクエストはエラーになります。
Webmockがスタブする対象から除外することができます。

# スタブ登録されていないリクエストはすべて許可する
WebMock.allow_net_connect!

# localhostへのリクエストはすべて許可する
WebMock.disable_net_connect!(allow_localhost: true)

# 特定のホストへのリクエストはすべて許可する
WebMock.disable_net_connect!(allow: 'www.example.org')

Rackミドルウェアを使ってスタブする

WebmockはRackミドルウェアを利用することができます。

JSON
json/hello.json
{
  "message": "Hello Webmock!"
}
Rackミドルウェアを作成
fake_rack.rb
require 'sinatra/base'

class FakeRack < Sinatra::Base
  post '/hello' do
    json_response 201, 'hello.json'
  end

  private

    def json_response(response_code, file_name)
      content_type :json
      status response_code
      File.open(File.dirname(__FILE__) + '/json/' + file_name, 'rb').read
    end
end
StubにRackミドルウェアを登録
rack_stub.rb
require 'bundler'
Bundler.require

require 'webmock'
require 'faraday'
require 'faraday_middleware'
require_relative 'fake_rack'
include WebMock::API

WebMock.enable!

client = Faraday.new(url: 'http://www.example.com') do |conn|
           conn.request  :json
           conn.response :json
           conn.adapter  Faraday.default_adapter
         end

# rackミドルウェアを登録
stub_request(:any, /www.example.com/).to_rack(FakeRack)

res = client.post '/hello'

pp "status: #{res.status}, body: #{res.body}" #=> "status: 201, body: {\"message\"=>\"Hello Webmock!\"}"

Rack::JsonSchemaを使ってスタブする

Rack::JsonSchema はJson Schemaを利用したRackミドルウェアです。
Rackミドルウェアなので、Webmockでも利用することをができます。

JsonSchema

webmock-sample/examples/json/schema.json

StubにRackミドルウェアを登録
rack_stub_with_rack_json_schema.rb
require 'bundler'
Bundler.require

require 'webmock'
require 'faraday'
require 'faraday_middleware'
require 'rack-json_schema'
include WebMock::API

WebMock.enable!

client = Faraday.new(url: 'http://www.example.com') do |conn|
           conn.request  :json
           conn.response :json
           conn.adapter  Faraday.default_adapter
         end

schema_file  = File.open(File.dirname(__FILE__) + '/json/schema.json', 'rb').read
local_schema = JSON.parse(schema_file)

mock_rack = Rack::Builder.new do
              use Rack::JsonSchema::Mock, schema: local_schema
              run ->(env) { [404, {}, ["Not Found"]] }
            end

stub_request(:any, /www.example.com/).to_rack(mock_rack)

res = client.get '/users'

pp "status: #{res.status}, body: #{res.body}" #=> "status: 200, body: [{\"id\"=>\"01234567-89ab-cdef-0123-456789abcdef\", \"name\"=>\"murajun1978\"}]"

まとめ

今更感がハンパないですがまとめてみました:sweat_smile:
外部サービスのリクエストをまるっぽスタブしたいときはRackミドルウェアが便利ですね。
個人的にはJSONを使ってスタブするのがよさげでした。

Happy Hacking٩( ‘ω’ )و

43
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
24