その他
    ホーム 技術発信 DoRuby ENVを扱うときに気を付けている2つのこと
     

    ENVを扱うときに気を付けている2つのこと

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    自分がRubyでENVを使ったコードを書くときに気をつけていることは、「`ENV.[]` より `ENV.fetch` を使う」と「環境変数の値に関わるテストは`[]`メソッドをstubする」です。 以下でその理由について解説します。

    ENV.[] ではなく ENV.fetch を使う

    # こうではなく
    ENV['hoge']
    
    # こう書く
    ENV.fetch('hoge')
    

    理由は以下のとおり

    • ENV.[] 場合、環境変数が未定義だと nil になる
      • 環境変数の参照している箇所ではなく、その取得した値を利用する箇所で想定外の挙動となり原因を見つけるのに時間が取られる。
      • ENV['hoge']' || 'default' のようにnilとなるのを防ぐことはできるが、忘れる場合があり確実じゃない。
    • ENV.fetch の場合、環境変数が未定義だと例外が発生する
      • ENV.fetch の箇所で例外が発生するので環境の不備、あるいはコードの不備であることがすぐにわかる
      • ENV.fetch('hoge', 'default') のように第2引数を使えば環境変数が未定義の場合のデフォルト値が指定できる。

    使い捨てのコードや自分しか触らないプライベートなコードであれば、ENV.[] でも良いですが、プロダクションなコードではfetchを使う方がメリットが大きいと考えます。

    Rspec では ENV[] で直接値を書き換えず必ず stub する

    # こうではなく
    it "xxx" do
      # spec 実行前の値をバックアップして書き換え
      @env_backup = ENV['hoge']
      ENV['hoge'] = 'fuga'
    end
    
    after do
      # spec 実行後にもとの値に戻す
      ENV['hoge'] = @env_backup
    end
    
    
    # こう書く
    before do
      allow(ENV).to receive(:[]).and_call_original
      allow(ENV).to receive(:[]).with('hoge').and_return('fuga')
    end
    

    理由は以下のとおり

    • 前者の場合、環境変数のスコープはグローバルなため影響がグローバルに波及する
      • after do ... end で元に戻すのを忘れた場合、タイミングによって spec が失敗する状況になり、その調査に時間が取られる。
      • 実際には試したことないが、specを並列に実行させた場合にも相互に影響が出る?
    • 後者の場合、影響範囲は実行中のspecの中だけで、値を戻し忘れるということも発生しない。

    参考: RspecでENVをどうstubするのがよいのか – Qiita

    まとめ

    • ENV.[] より ENV.fetch を使ってコードが動作するために環境変数の設定が必要であることをコードで明示しよう。
    • RspecではENV.[]メソッドをstubすることで影響範囲を限定しよう
    記事を共有
    モバイルバージョンを終了