Microservices化などでRailsからも外部サービスへリクエストすることが増えてきました。
テストなどで実際に外部サービスへリクエストしてしまうとなにかとね、、
なので、Webmockを使ってスタブしてみましょう。
READMEにも書かれてますが、WebmockはRubyのHTTPライブラリをスタブするだけで、フロントからの外部リクエストをスタブすることができないので注意が必要です
フロントからのリクエストをスタブしたい場合は、1日目に @chimame さんが書いてくれてるので参考にしてください
featureスペックでクライアント(JavaScript)側から呼び出すRequestをモックする
この記事のサンプルコード murajun1978/webmock-sample
リクエストをスタブする
Webmockにスタブするリクエストにレスポンスを設定して登録します。
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などマッチしたリクエストをスタブに登録します。
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
{
"message": "Hello Webmock!"
}
Rackミドルウェアを作成
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ミドルウェアを登録
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ミドルウェアを登録
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\"}]"
まとめ
今更感がハンパないですがまとめてみました
外部サービスのリクエストをまるっぽスタブしたいときはRackミドルウェアが便利ですね。
個人的にはJSONを使ってスタブするのがよさげでした。
Happy Hacking٩( ‘ω’ )و