Rails
RubyOnRails

Railsのテスト環境でcookieを使う時の工夫

Railsのテスト環境において暗号化cookieを使うとちょっとしたエラーが出る。

こんなの
NoMethodError: undefined method `signed' for #<Rack::Test::CookieJar:0x0000000XXXXXXXX>

これは、テスト環境においてRailsが使用しているライブラリが本番環境(および開発環境)のそれと違うために起きる問題...らしい

Railsチュートリアル内の「テスト内ではcookiesメソッドにシンボルを使用できない」という問題
↑参考にさせていただきました記事

暗号化(signed)と同様に、永続化(permanent)cookieも使えない。
このままではテストができないため、なんとかする。


まずは、cookieを一元的に管理する関数をApplicationHelperで定義する。

app/helpers/application_helper.rb
module ApplicationHelper

  ...

  #cookie取得
  def getcookie(tag)
    cookies.signed[tag]
  end
  #cookie保存
  def setcookie(tag, value)
    cookies.permanent.signed[tag] = value
  end
  #cookie削除
  def deletecookie(tag)
    cookies.delete(tag)
  end
end

そして、ソースコードからcookieを呼び出す時は、必ずこの関数を使って呼び出すようにする。

続いて、テスト環境でのみ、この関数をpermanentやsignedを使わないものに書き換える。

test_helper.rbというファイルにおいて、テスト環境でのみ使用する関数を定義することが出来る。ここで前述のApplicationHelperモジュールを上書きする。

test/test_helper.rb
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

class ActiveSupport::TestCase
  fixtures :all

  ...

  module ApplicationHelperFixes
    #テスト用に再定義を行う

    #cookie取得
    def getcookie(tag)
      cookies[tag.to_s]  #signed使わない
    end
    #cookie保存
    def setcookie(tag, value)
      cookies[tag.to_s] = value  #signed,permanent使わない
    end
    #cookie削除
    def deletecookie(tag)
      cookies.delete(tag.to_s)  #これはとくに変わりなし
    end
  end
  #変更を適用する
  ApplicationHelper.send :prepend, ApplicationHelperFixes
end

これでテストを実行すると、こちらの関数が適用されるために前述のエラーは出なくなった。
Rubyのオープンクラスの凄さを思い知った。


これが正しいテストヘルパーの使い方なのかとか、他の解決方法とか、弊害とかまったくわからないけど、とりあえず解決したので投稿させていただきました。
何か間違いがあれば暖かく教えていただけると幸いです。


追記:2018/1/20 一部test_helperのコードに誤りがあったため修正しました。