この記事でわかること
request spec や feature spec ではない、 cookies だけをどうにかして取り出してテストを書きたいフレンズが、テストを書けるといいなぁって思えるようになる。 ただし、厳密には違う。違うんだ……どうしたらいんだ……教えてくれ…………(ほんとう?
背景
例えば以下のようなコードでテストを書きたかった
# app/models/state.rb # めっちゃだめなクラス名だな…… class State class CookiesAdapter def initialize(cookies) @cookies = cookies end def transition!(key) @cookies['state_transition'] = { value: key } end def in?(key) @cookies['state_transition'] = end end def initialize(adapter) @adapter = adapter end def transition!(key) @adapter.transition!(key) end def in?(key) @adapter.in?(key) end end class HogeController def show @state = State.new(State::CookiesAdapter.new(cookies)) end # ... end
State
インスタンスの振る舞いは、実際には hogeAdapter の同名のメソッドを呼ぶことで、上の実装では CookiesAdapter
しかないが、まぁRedisなりなんなりのAdapterがあればいい感じに振る舞いを分離できて幸せそう。
AdapterPattern のようなナニだ。
で、Cookiesを使いたい時に、 Rails では ActionDispatch::Cookies
に実装*1があり、他にもあるが一番わかり易いのが ActionDispatch::Request#cookies_jar
で*2、 Cookies::CookiesJar.build
経由で cookies_jar
を作って、その alias として cookies
名*3でのアクセスが実現できている。
困ること
- Cookies を直接インスタンス化するために必要なパラメーターがわからん(調べればいいんですが)
- request spec として、リクエストが透けた形で↑のモデルのテストを書きたくない
- feature spec として以下略
- ActionController のインスタンス化でもいいけど、なんかもう少し上手いやつないかなぁ
ということでテストの書き方二種
二種? というのは、rails のバージョンで異なるため。古いバージョンとかは知らない。4.2は古いっていうのは、はいそうですね。
rails 4.2
RSpec.describe State::CookiesAdapter do let(:cookies) { ActionDispatch::Request.new({}).cookies }
え、なにそれ辛い。辛いというか、 とくに new({})
あたりが、「本当にそうなのか」がワカラナイ。
一応、 Rails.application.env_config
でよいっぽいというStackOverflowの気持ちを見ることができるが、ほんと〜?となる。
unit testing - Setup cookie.signed in Rails 5 controller integration tests - Stack Overflow
rails 5
RSpec.describe State::CookiesAdapter do let(:cookies) { ActionDispatch::Request.empty.cookie_jar }
https://github.com/rails/rails/blob/master/actionpack/test/dispatch/cookies_test.rb#L12
rails が 自らのテスト↑で @request
を Request.empty
で作成してそこから cookie_jar を取ってる。( 厳密には cookies_jar )
なんか結局イマイチだけど、まぁ rails がそうやってるなら、まぁいいんじゃないかな? となる。
おわりに
rails5
を使おう- そうでないなら
ActionDispatch::Request.new({}).cookie_jar
で一応取れる。ほんと〜?
*1:https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/cookies.rb#L170
*2:https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/cookies.rb#L11
*3:https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/cookies.rb#L13