【Ruby】faradayを利用した外部API連携クラスの作成手順の記事で、Faradayを利用した外部APIとの連携方法について紹介しました。
外部APIを利用したロジックのテストコードでは、実際のAPIを利用するのではなくHTTPリクエストをスタブ化するのが一般的です。
Railsではwebmockというgemを利用することでHTTPリクエストのスタブ化ができます。
今回はWebMockを利用して、外部APIと連携したロジックのテストコードを作成する方法について紹介します。
目次
テストコードの対象となるクラス
今回はQiitaClientAPI
というQiita APIと連携するクラスのテストコードを作成します。
クラスにはget_items
という記事一覧をQiitaから取得するメソッドが実装されています。
具体的なソースコードは以下の通りです。
lib/qiita_api_client.rb
class QiitaApiClient
class HTTPError < StandardError
def initialize(message)
super "connection failed: #{message}"
end
end
class << self
def connection
Faraday::Connection.new('https://qiita.com') do |builder|
builder.authorization :Bearer, "#{Rails.application.credentials.qiita[:token]}"
builder.request :url_encoded # リクエストパラメータを URL エンコードする
builder.response :logger # レスポンスを標準出力する
builder.adapter Faraday.default_adapter # アダプターの選択。デフォルトはNet::HTTP
builder.response :json, :content_type => "application/json" # レスポンスボディをJSONパースする
end
end
def get_items
begin
response = connection.get(
'/api/v2/items'
)
response.body
rescue Faraday::ConnectionFailed => e
raise QiitaApiClient::HTTPError.new(e.message)
end
end
end
end
下準備
テストコードを実行するための準備を行ます。
RSpecのセットアップ
今回はテスティングフレームワークにRSpecを利用します。
rspec-railsをGemfileに追加します。
group :development, :test do
gem 'rspec-rails'
end
gemのインストールとRSpecのセットアップを行ます。
$ bundle install
$ rails generate rspec:install
webmockのインストール
webmockをGemfileに追加し、インストールします。
gem 'webmock'
$ bundle install
テストコードの実装
以下ではWebMockを利用したテストコードの記述方法について紹介します。
正常系のテスト
正常系のテストコードは以下の通りです。
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
before do
WebMock.enable! # WebMockの有効化
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
let(:response_body) { [{ "title": "test" }].to_json }
before do
WebMock.stub_request(:get, "https://qiita.com/api/v2/items").
with(
headers: {'Authorization' => "Bearer 123"}
).
to_return(
body: response_body,
status: 200,
headers: { 'Content-Type' => 'application/json' }
)
end
it 'データが取得できること' do
expect(QiitaApiClient.get_items).to eq(JSON.parse(response_body))
end
end
end
WebMock.enable!
でWebMockを有効化し、WebMock.stub_request
の箇所でHTTPリクエストのスタブを作成しています。
WebMockを利用することで「どういったリクエストに対して、どういったレスポンスを返す」という挙動が記述できます。これにより、外部API経由でデータのやりとりを行う状況が擬似的に作成できます。
なおbefore
に記載されているallow(Rails.application.credentials)
の箇所はアプリケーションコードに記載されているRails.application.credentials.qiita[:token]
に対してダミー値をセットするためのものです。
異常系(例外発生)のテスト
アプリケーションコードでは外部APIと正常に通信できなかった場合、エラーメッセージを添えてQiitaApiClient::HTTPError
という例外を発生させています。
例外が発生したことを確認する異常系のテストコードは以下の通りです。
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
before do
WebMock.enable!
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
let(:response_body) { { "message": "error_message", "type": "error_type" }.to_json }
before do
WebMock.stub_request(:get, "https://qiita.com/api/v2/items").
to_raise(Faraday::ConnectionFailed.new("some error"))
end
it '例外が発生すること' do
# 例外のテストはexpect()ではなくexpect{}なので注意
expect{QiitaApiClient.get_items}.to raise_error(QiitaApiClient::HTTPError, "connection failed: some error")
end
end
end
WebMockのto_raise
で例外が発生するスタブを作成し、expectのraise_error
で例外が発生していることを確認しています。
最終的なテストコード
今回紹介した正常系と異常系をまとめた最終的なテストコードは以下のようになります。
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
let(:qiita_base_uri) { 'https://qiita.com/api/v2' }
before do
WebMock.enable!
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
subject { QiitaApiClient.get_items }
context '成功' do
let(:response_body) { [{ "title": "test" }].to_json }
before do
WebMock.stub_request(:get, "#{qiita_base_uri}/items").
with(
headers: {'Authorization' => "Bearer 123"}
).
to_return(
body: response_body,
status: 200,
headers: { 'Content-Type' => 'application/json' }
)
end
it 'データが取得できること' do
expect(subject).to eq(JSON.parse(response_body))
end
end
context '失敗' do
before do
WebMock.stub_request(:get, "#{qiita_base_uri}/items").
to_raise(Faraday::ConnectionFailed.new("some error"))
end
it '例外が発生すること' do
expect{subject}.to raise_error(QiitaApiClient::HTTPError, "connection failed: some error")
end
end
end
end
まとめ
WebMockを利用して、外部APIと連携したロジックのテストコードを作成する方法について紹介します。
WebMockを利用したテストコードのフローは以下のようになります。
- Webmock.enable!でWebMockを有効化する
- WebMock.stub_requestでHTTPリクエストのスタブを作成する
- 外部APIを利用するメソッドを実行し、実行結果の検証を行う
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!