概要
Geocoder.search('検索キー')
をrspecのテストで使いたいとき、stubは以下の通り。
before do
Geocoder.configure(lookup: :test)
Geocoder::Lookup::Test.add_stub('検索キー',[検索結果のハッシュ])
end
説明
stubを使わなかった時のエラー例
Geocoder.search('検索キーワード')を使ったコードに対して、ネットワーク接続が出来ない環境でrspecを実行するとエラーがでる。
これは、git geocoderに書かれているとおり、'検索キーワード'に対応するstubを作れば解決する。
以下に、解決例を書く。
解決例
シナリオ
place_search_controllerというコントローラに /place_search/?keyword=東京
のルーティングでアクセスし、keywordを元にGeocode.search(keyword)を使う機能を実装後、テストコードを書く。
実装した機能
Geocoderを使ってkeywordで検索したとき、#indexは以下の結果を返す
- 結果が得られればステータス200でview(views/place_search/index.html.erb)を表示
- 結果が得られなければステータス500でview(errors/error_500.html.erb)を表示する
class PlaceSearchController < ApplicationController
def index
geo = Geocoder.search(params[:keyword])
if geo.present?
@location = Geocoder.search(params[:keyword])[0].data["geometry"]["location"] # latitudeとlongitudeを取得して、viewで使うことを想定した動き(viewは省略)
else
render template: 'errors/error_500', status: 500, layout: 'application', content_type: 'text/html' # 検索ヒットが0件の時は 500番を返す
end
end
end
rspecテストコード
- keyword="東京"で検索したときはステータス200番を返す
- keyword="ダメなキーワード"で検索したときはステータス500番を返す
上記2点をテストするコードは以下の通り
require 'spec_helper'
describe PlaceSearchController do
describe '#index' do
before do
Geocoder.configure(lookup: :test)
Geocoder::Lookup::Test.add_stub(
'東京', [{
'geometry' => { 'location' => { 'lat' => 35.7090259, 'lng' => 139.7319925 } }
}]
)
Geocoder::Lookup::Test.add_stub(
'ダメなキーワード', []
)
end
it '東京で検索したときはステータス200番を返す' do
get '/place_search', {keyword: '東京'}
expect(response.status).to eq 200
end
it 'ダメなキーワードで検索したときはステータス500番を返す' do
get '/place_search', {keyword: 'ダメなキーワード'}
expect(response.status).to eq 500
end
end
end
これでOK。
解説
Geocoder.search('検索キー')は、検索キーを位置情報API(初期値はgoogle)に問い合わせることで位置情報を得ています。よって、外部ネットワークに接続できない場合はGeocoder.searchが機能しないため、関連するテストコードが全てエラーとなります。
テストのためだけに、外部ネットワークに無駄にアクセスすることは推奨されないため、CI環境では外部へのネットワーク接続が不可の場合があります。
このときに使うのがstubという仕組みであり、Geocoderではすでにその仕組みを用意していますので、活用するだけです。
Geocoder.configure(lookup: :test)
lookupは検索するapiを設定するためのキーです。これをtestと指定することにより、以降のGeocoder.searchが以下で示すstubに対して行われるようになります。
Geocoder::Lookup::Test.add_stub('東京', [ 省略 ])
stubを指定します。フォーマットは、 Geocoder::Lookup::Test.add_stub('検索キー',[検索結果のハッシュ])
です。
検索キーは Geocoder.search('東京')
であれば 東京 です。
検索結果のハッシュは、Geocoder.configureの設定によって異なります。わからない場合は、 rails c
で 下記のコマンドを実行してその結果を入れてください。
> Geocoder.search('検索キー')[0].data.to_hash
例えば検索キーとして 東京 を指定した場合は以下の通りなので、それを検索結果のハッシュとして貼り付ければstubとして使えます。(以下は見やすいように整形しています。)
{ 'address_components' => [{ 'long_name' => 'Tokyo',
'short_name' => 'Tokyo',
'types' => %w(colloquial_area locality political) },
{ 'long_name' => 'Tokyo', 'short_name' => 'Tokyo', 'types' => %w(administrative_area_level_1 political) },
{ 'long_name' => 'Japan', 'short_name' => 'JP', 'types' => %w(country political) }],
'formatted_address' => 'Tokyo, Japan',
'geometry' => { 'bounds' => { 'northeast' => { 'lat' => 35.8175167, 'lng' => 139.9198565 },
'southwest' => { 'lat' => 35.5208603, 'lng' => 139.5629048 } },
'location' => { 'lat' => 35.7090259, 'lng' => 139.7319925 },
'location_type' => 'APPROXIMATE',
'viewport' => { 'northeast' => { 'lat' => 35.8175167, 'lng' => 139.9198565 },
'southwest' => { 'lat' => 35.5208631, 'lng' => 139.5629048 } } },
'place_id' => 'ChIJXSModoWLGGARILWiCfeu2M0', 'types' => %w(colloquial_area locality political) }
なお、検索結果のハッシュは機能から呼び出している箇所の指定だけでもいいです(もちろん全部書いてもいいですが、冗長ですよね)。今回の機能では、'location'の箇所しか呼び出していないので、以下箇所だけstubに記述しました。
Geocoder::Lookup::Test.add_stub(
'東京', [{
'geometry' => { 'location' => { 'lat' => 35.7090259, 'lng' => 139.7319925 } }
}]
)