Railsのインテグレーションテストでcookies.signedを使いたい

petitviolet
3 min readJun 24, 2019

tl;dr

非テストコード内でcookies.signedを使っている場合は、テストコード内においてRack::Test::CookieJar#signedを書き換えればOK。
signed以外にもencryptedとかpermanentも同様に対応できるはず。

参考

Signed cookies not available in controller specs — rspec-rails 3.5.0, rails 5.0 · Issue #1658 · rspec/rspec-rails

インテグレーションテストにおける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とかも同じように対応すれば問題なさそう。

--

--