やりたいこと
手順
Custom Search JSON API | Programmable Search Engine を使って開発をしていたときのこと。
Google公式が用意しているAPI利用gem googleapis/google-api-ruby-client: REST client for Google APIs を使い、検索結果を取得するクラスを作成した。
たとえば、こんな感じ。
class GoogleSearch def initialize(query:, url:, api_key:, cse_id:) @query = query @url = url @api_key = api_key @cse_id = cse_id end ~
初期化時にAPIキーを入れて使うような設計になっている。
今回、APIへのリクエストにたいするレスポンスをwebmockでスタブ登録して使おうとした時、すこし手こずった。
テストはminitestを使用しているが、RSpecでも根幹の部分は変わらないと思う。
テストファイルはこんな感じ。
test/models/google_search_test.rb
# frozen_string_literal: true require 'test_helper' class AmazonTest < ActiveSupport::TestCase setup do stub_google! @google = GoogleSearch.new( query: 'ハンターハンター', url: "https://ja.wikipedia.org/wiki/HUNTER%C3%97HUNTER", api_key: 'mock_api_key', cse_id: 'mock_cse_id' ) end #リクエスト時に送ったURLが検索順位1位であることのテスト test "#fetch_ranking" do assert_equal 1, @google.fetch_ranking end end
- 「ハンターハンター」と検索している”てい”
https://ja.wikipedia.org/wiki/HUNTER%C3%97HUNTER
というURLが何位なのかチェックしてほしい”てい”mock_api_key
:APIキーをいれてる”てい”mock_cse_id
:検索エンジンIDを入れている”てい”
これらはすべて「てい」なので、Web API にリクエストを送るフリをしているだけ。本当は Webmock がレスポンスを返してくれる。
このテストファイル内でスタブ登録もできるが、実際に開発するなら別ファイルに切り出すと思う。今回もそのようにした。
test/supports/stub_helper.rb
module StubHelper def stub_google! json = File.read("#{Rails.root}/test/fixtures/search_results.json") stub_request(:get, "https://customsearch.googleapis.com/customsearch/v1?cx=mock_cse_id&key=mock_api_key&num=100&q=ハンターハンター").to_return(status: 200, body: json, headers: { "Content-Type" => "application/json" }) end end
- スタブをヘルパーにまとめて登録している
"#{Rails.root}/test/fixtures/search_results.json"
というファイルを作り、あらかじめ取得しておいたJSONのレスポンスを設置
ここでのポイントは、"https://customsearch.googleapis.com/customsearch/v1?cx=mock_cse_id&key=mock_api_key&num=100&q=ハンターハンター"
と設定している点。
これはテストファイルでの
@google = GoogleSearch.new( query: 'ハンターハンター', url: "https://ja.wikipedia.org/wiki/HUNTER%C3%97HUNTER", api_key: 'mock_api_key', cse_id: 'mock_cse_id' )
に合わせている。
これでテストは通過した。
$ rails test test/models/google_search_test.rb Running via Spring preloader in process 61289 Run options: --seed 41283 # Running: . Finished in 0.110767s, 9.0280 runs/s, 9.0280 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
学び
当初は、以下のようにスタブを登録していたがエラーが出ていた。
#ダメだった方法 stub_request(:post, "https://customsearch.googleapis.com/customsearch/v1").~
これでエラーが出て、ずっと「なんでやね〜ん」となっていた。
今考えると、ここでのリクエストとは、検索エンジンで検索する行為と同じことだ。そりゃこのURLでは何も返ってこないわけだ。POSTリクエストではなく、GETリクエストにするのも確かにそうだ。
Webmockのエラーメッセージには「GETで"https://customsearch.googleapis.com/customsearch/v1?cx=mock_cse_id&key=mock_api_key&num=100&q=ハンターハンター"
ってな感じでリクエストしたらOKやで〜」と出ていた。やっぱりエラーメッセージをよく読むことの重要性を身をもって痛感した😅
Webmockでスタブ登録するうえでは、HTTPメソッドとリクエストURIの設定が重要なんだとわかった。
参考ファイル
gemfile
group :development, :test do gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'webmock' end
test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test' require_relative '../config/environment' require 'rails/test_help' require 'webmock/minitest' #minitest用のwebmockを使用 require "supports/stub_helper" #スタブヘルパーをrequire # WebMock.allow_net_connect! class ActiveSupport::TestCase # Run tests in parallel with specified workers parallelize(workers: :number_of_processors) # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... include StubHelper #ここで使えるようにしている end