Journey

技術に関することと覚書と

ActiveRecordのtakeメソッドがテスタブルだった

Railsにおいてある特定個数の要素がほしいときに以下のようなコードをよく書くと思います。

Article.most_recently.limit(5)

ただこのように書いてしまうと、 limitrailsのメソッドのためテストコードが書きにくくなってしまいます。具体的な例を上げると、これをコントローラーのユニットテストをしようとしたときにスタブにするコードが以下のようなものになります。

let(:most_recently) { double('most_recently', limit: [double('article')]) }

before do
  allow(Article).to recevive(:most_recently) { most_recently }
end

most_recently メソッドの出力として、limit メソッドを持つスタブを登録して、その limit で配列を返しています。ただ自分の場合は most_recently の時点で pure rubyの配列として扱い出したいので limit なんてものは介したくありません。

そこでrailsって take メソッドもあったよなーと思い実行してみるとちゃんと limit もつけてくれてました。

Article.most_recently.take(5)
Article.most_recently.limit(5).to_a

railstakeソースコードを見ると1行目のコードを実行すると、2行目と同じ処理をしていました。 take を引数付きで呼ぶと、その引数で limit をつけてSQLを発行した結果を返してくれています。これを使えば先程のテストコードは以下のようにできます。

before do
  allow(Article).to recevive(:most_recently) { [double('article')] }
end

limit をpure rubyにもある take に置き直したことで、スタブにしなくて良くなりました。個人的にはすごく嬉しい発見です。 ただ to_a していることから分かる通り、返り値が ActiveRecord_Relation ではなく Array なのでそこには注意してください。