はじめに
下記記事の続きです。
よく分からないので教えて下さい〜と呟いたらRails界隈で超有名な伊藤淳一さんからのコメントいただけて感動しました。
@naichilab さん、こんにちは。ざーっとブログを読ませてもらいましたが、こんな感じで十分だと思いますよ。むしろわかりやすかったです。重複をなくそうとすると可読性が落ちてくることがあるので、テストコードは多少重複してもいいと思います。
— Junichi Ito (伊藤淳一) (@jnchito) 2016, 1月 19
コメントいただけただけで嬉しかったですが、 その後の会話でDRY化する方法についても教えていただけたのでメモしておきます。
会話全文は上記リンクから。
題材
前回の記事ではUserControllerに対するRSpec
のテストを書いていました。
その中で自分が気にしていたのはPost
のテスト
describe 'Post #create' do context '有効なパラメータの場合' do before do @user = attributes_for(:user) end it 'リクエストは302 リダイレクトとなること' do post :create, user: @user expect(response.status).to eq 302 end it 'データベースに新しいユーザーが登録されること' do expect{ post :create, user: @user }.to change(User, :count).by(1) end it 'rootにリダイレクトすること' do post :create, user: @user expect(response).to redirect_to root_path end end end
有効なパラメータの場合
という1つの状態(context)に対して
3つの実行可能なサンプル(example)を書いています。
UsersController Post #create 有効なパラメータの場合 リクエストは302 リダイレクトとなること データベースに新しいユーザーが登録されること rootにリダイレクトすること
具体的には下記3つのexampleが同じ状態を対象としないとダメなんですよね。
- リクエストは302 リダイレクトとなること
- データベースに新しいユーザーが登録されること
- rootにリダイレクトすること
それなのにpost :create, user: @user
をコピペしながら書いてる自分がいて、
これはそのうち書き間違えるな、と。
getとかだと間違ってても気づきもしないなーと。
DRYにする方法
目標は3つに分かれたpost
をまとめることですね。
とりあえず教えて頂いた方法を載せていきます。
伊藤さんも仰られてますがDRY化しすぎると可読性が落ちることがあるので採用するかは判断が必要ですね。
1. exampleをまとめる方法
1つのit(example)
の中に3つのエクスペクテーション(期待すること)
をまとめてしまう方法。
これは分かりやすいですね。
ただexample(it で始まる 1 行)一つにつき、結果を一つだけ期待する。
というRSpecの原則とずれちゃう感じ。
2. letにラムダ式を入れておいてcallで呼び出す方法
これはこの記事を見てうまく行かなかったことを伝えたらcall
が必要だよと教えてくれた内容。
call
については調べてないけど書かないと変数と区別つかないからかな?
3. その場でヘルパーメソッドを定義する方法
これは驚いた。describe
、before
、after
とか決められた関数しか呼べないと勝手に思い込んでた。(C#に慣れてて)
自分が選んだ方法
今回は2. letにラムダ式を入れておいてcallで呼び出す方法
を使うことに決めました。
exampleをまとめる方法は分かりやすいけど1example=1expectの原則
が納得できて好きなので破る必要ないなーと。
その場でメソッドを作る方法も読みやすいけど好き勝手書いて結局読みづらくなりそうだから。
let
は今後必然的に多用しそうだし十分読みやすいと判断。
しばらくこれで書いてみよう〜。
伊藤さん分かりやすくに教えていただいてありがとうございました〜!!