naichi's lab

3日後の自分(他人)への書き置き

Ruby on Rails、RSpecを使ってコントローラのテストを書いてみる その2 ちょっとDRY化

f:id:naichilab:20160116161543p:plain

はじめに

下記記事の続きです。

blog.naichilab.com

よく分からないので教えて下さい〜と呟いたらRails界隈で超有名な伊藤淳一さんからのコメントいただけて感動しました。

コメントいただけただけで嬉しかったですが、 その後の会話でDRY化する方法についても教えていただけたのでメモしておきます。

会話全文は上記リンクから。

DRY(Don't repeat yourself)

題材

前回の記事では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. その場でヘルパーメソッドを定義する方法

これは驚いた。describebeforeafterとか決められた関数しか呼べないと勝手に思い込んでた。(C#に慣れてて)

自分が選んだ方法

今回は2. letにラムダ式を入れておいてcallで呼び出す方法を使うことに決めました。

exampleをまとめる方法は分かりやすいけど1example=1expectの原則が納得できて好きなので破る必要ないなーと。

その場でメソッドを作る方法も読みやすいけど好き勝手書いて結局読みづらくなりそうだから。

letは今後必然的に多用しそうだし十分読みやすいと判断。

しばらくこれで書いてみよう〜。


伊藤さん分かりやすくに教えていただいてありがとうございました〜!!