Faraday の スタブテスト
こんにちは、クラスメソッドの稲毛です。
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\"}]"