Just do IT

学んだことを吐き出す場所です。

webmock を使って外部API をローカルと CI でテストしたい

やりたいこと

  • CircleCIで外部API/Web APIにアクセスしている箇所をテストしたい
  • テスト環境上で本番APIにリクエストを送りたくない

前提

$ ruby -v
ruby 2.7.1

$ rails -v
Rails 6.0.3.2

その他

  • webmockを使ってAPIレスポンスをスタブしていること
  • VCRは使っていない

問題

以下のような記述でAPIにアクセスしているとする。

GoogleSearch.new(
    query: @article.keyword, 
    url: @article.url, 
    api_key: ENV["GOOGLE_API_KEY"], 
    cse_id: ENV["GOOGLE_CSE_ID"]
)

起きていた問題

  • CIが通らない
  • テスト環境なのに本番APIへリクエストを投げてしまう
    • WebMock.allow_net_connect!をしているから当然なのだけど...

つまり、コード自体にはAPIキーを書いておいて、ローカルテストやCIではAPIレスポンスはスタブを呼び出したい。

解決

手順はこちら。

  • CircleCIの環境変数APIキーを登録する
  • スタブに登録するURLの中にAPIキーが入る部分があれば、環境変数として記述する

ひとまず、WebMock.allow_net_connect!の記述は削除する。

CircleCIの環境変数APIキーを登録する

今回、以下の2つの環境変数を使う。

本来ローカルの bash_profile などに登録している環境変数の中身を、CircleCI の Environment Variables(環境変数)に登録する。

  • CIで該当プロジェクトのページへいく
  • Project settings
  • Environment Variables

f:id:K_Koh:20200915075333j:plain

スタブ登録したURLに環境変数をいれる

実際にはこんな感じで設定している。

def stub_google!
    json = File.read("#{Rails.root}/spec/factories/files/mock_bodies/search_results_1.json")
    stub_request(:get, "https://customsearch.googleapis.com/customsearch/v1?cx=#{ENV["GOOGLE_CSE_ID"]}&key=#{ENV["GOOGLE_API_KEY"]}&q=%E3%83%8F%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8F%E3%83%B3%E3%82%BF%E3%83%BC&start=1").to_return(status: 200, body: json, headers: { "Content-Type" =>  "application/json" })
  end

rewrite_logger/stub_helper.rb at master · kotakanazawa/rewrite_logger

このように、

をリクエスURIに含めている。

実際にHTTPリクエストをしてしまうのでは?

webmockはデフォルトでHTTP通信を不可にする。

よって、WebMock.allow_net_connect!をして通信許可をしない限り、スタブしたAPIレスポンスが返る。これでAPIキーを書きつつもテストではスタブを呼び出すことができた。