この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、クラスメソッドの稲毛です。
Rails のコントローラ内で Faraday を使用する機会があり、RSpec の Example をどのように書けば良いのか調べてみました。
目標
架空の API(http://www.example.com/api/foobar) にスタブを設定し、リクエストによりそのレスポンスが得られる事を確認します。
Spec
スタブで置き換えれば良いのは Faraday.new で生成される Fraday::Connection オブジェクトということで、Spec ファイルにはスタブの Connection を let! で用意しました。Using Faraday for testing
let!(:stub_connection) do
Faraday.new do |conn|
conn.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/api/foobar') do
[ 200, {}, JSON.generate([ { id: 1, name: "Foo" }, { id: 2, name: "Bar" } ]) ]
end
end
end
end
通常は conn.adapter メソッドの引数として Faraday.default_adapter が用いられる所を、第一引数に :test 、第二引数に Faraday::Adapter::Test::Stubs オブジェクトとなっているのがスタブならではのようです。
Faraday.new(url: 'http://www.example.com') do |conn|
conn.request :url_encoded
conn.response :logger
conn.adapter Faraday.default_adapter
end
Faraday::Adapter::Test::Stubs オブジェクトを生成する際のブロック内でリクエストに対応するレスポンスを指定します。ここでは GET メソッドで http://www.example.com/api/foobar がリクエストされたら JSON をボディとして HTTP ステータス 200 を返すようにしました。
stub.get('/api/foobar') do
[ 200, {}, JSON.generate([ { id: 1, name: "Foo" }, { id: 2, name: "Bar" } ]) ]
end
リクエストパスによって異なるレスポンスを返すよう、複数のケースを設定することができます。
stub.get('/api/foobar') do
[ 200, {}, JSON.generate([ { id: 1, name: "Foo" }, { id: 2, name: "Bar" } ]) ]
end
stub.show('/api/foobar/1') do
[ 200, {}, JSON.generate({ id: 1, name: "Foo" })]
end
stub.show('/api/foobar/2') do
[ 200, {}, JSON.generate({ id: 2, name: "Bar" })]
end
:
Spec ファイルは以下のようになりました。
foobar_controller_spec.rb
require 'rails_helper'
RSpec.describe FoobarController, :type => :controller do
describe 'GET index' do
let!(:stub_connection) do
Faraday.new do |conn|
conn.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/api/foobar') do
[ 200, {}, JSON.generate([ { id: 1, name: "Foo" }, { id: 2, name: "Bar" } ]) ]
end
end
end
end
let(:request) { get :index, format: :json }
before do
allow(controller).to receive(:connection).and_return(stub_connection)
request
end
it { expect(response).to be_success }
end
end
before ブロックでコントローラの connection メソッドに対して stub_connection を設定しています。RSpec Mocks 3.0
Controller
Spec では、コントローラの connection メソッドをスタブと置き換える事を想定したので、コントローラでの Faraday.new は connection メソッドで返されるように実装します。
コントローラは以下のようになりました。
foobar_controller.rb
class FoobarController < ApplicationController
def index
response = connection.get '/api/foobar'
p response.body # レスポンスボディをコンソールへ出力
render nothing: true
end
private
def connection
Faraday.new(url: 'http://www.example.com') do |conn|
conn.request :url_encoded
conn.response :logger
conn.adapter Faraday.default_adapter
end
end
end
結果
Spec を走らせた結果、レスポンスボディがスタブで指定したものになっていることが確認できました。
"[{\"id\":1,\"name\":\"Foo\"},{\"id\":2,\"name\":\"Bar\"}]"