Railsのインテグレーションテストでcookies.signedを使いたい
tl;dr
非テストコード内でcookies.signed
を使っている場合は、テストコード内においてRack::Test::CookieJar#signed
を書き換えればOK。signed
以外にもencrypted
とかpermanent
も同様に対応できるはず。
参考
インテグレーションテストにおけるcookie
例えばcookies.signed
を呼び出しているコードがあると、rails s
などで起動したアプリケーション上では問題なく動くが、インテグレーションテストを実行すると
NoMethodError: undefined method `signed’ for #Rack::Test::CookieJar:0x00007fcdbc1ceb20
というエラーが発生して死んでしまう。
これは実行する環境によってcookieはクラスが変わっているため。
- アプリケーションを実際に動かしている場合は
ActionDispatch::Cookies::CookieJar
- テストを実行している場合は
Rack::Test::CookieJar
これがダックタイピング…!
rails/railsのIssue #27145のコメントによるとActionController::TestCase
ではcookies.signed
をサポートするけどActionDispatch::IntegrationTest
ではサポートしない設計であるとのこと。
とはいえインテグレーションテストとして呼び出しているcontrollerの中でcookies.signed
を叩いていると死んでしまうのは困る。
解決策
そこで、cookies.signed
を呼ばれても問題なくしてしまおうというアプローチをとる。
# test_helper.rb
class Rack::Test::CookieJar
def signed
self
end
end
signed
が定義されていないならしてしまおうということ。Rubyのオープンクラスは柔軟で良い。
テストだしセキュリティはまあスルーしても問題ないでしょう。
もちろん必要であればcookies.encrypted
とかも同じように対応すれば問題なさそう。