patorashのブログ

方向性はまだない

Rspecで環境変数をstubしていたのが動かなくなった件(解決済)

小ネタです。rubocopのバージョンアップを行ったら、新しいルールで怒られが発生しました。

 C: [Correctable] Style/FetchEnvVar: Use ENV.fetch('FOO') or ENV.fetch('FOO', nil) instead of ENV['FOO'].

Correctableなので、bundle exec rubocop -Aで自動修正を行ったところ、ENV.fetch('FOO', nil)になりました👍

これでテストを実行したところ、思わぬエラーが発生😵

環境変数をstubしているテストが落ちる

環境変数によって、とある項目をチェックするかどうかを切り替えている処理がありまして、そのテストのために以下のようにしていました。

context '環境変数BARに0が設定されている場合' do
  before do
    allow(ENV).to receive(:[]).and_call_original
    allow(ENV).to receive(:[]).with('BAR').and_return('0')
  end

  it 'チェックされないこと' do
    # テストケース
  end
end

※この書き方は、以下の記事を参考にしています。

qiita.com

該当箇所のコードは、元々はこんな感じ。

if (ENV['BAR'] || '1') != '0'
  # チェックする
end

これが、rubocopのAutoCorrectによって、こうなりました。(カッコが多かったため、手でも修正しています)

if ENV.fetch('BAR', '1') != '0'
  # チェックする
end

これが全くstubされないように…😢

原因

これはstubの定義がENV['BAR']の場合にしか対応していないためです。この変更に対応するには、ENV#fetchの結果をstubしなければなりません。

解決方法

環境変数の参照の仕方のstubをfetch経由に変更します。

context '環境変数BARに0が設定されている場合' do
  before do
    allow(ENV).to receive(:fetch).and_call_original
    allow(ENV).to receive(:fetch).with('BAR', '1').and_return('0')
  end

  # 略
end

肝は、with('BAR', '1')のところで、with('BAR')だとstubされませんでした。きちんとデフォルト値まで渡さなければなりません。

まとめ

環境変数をちゃんとstubしているのに何故!?と5分くらい考えてしまいましたが、当然っちゃあ当然です😅 環境変数をfetch経由で受け取る修正をした際は、テストのstubも見直しましょう。