Everyday Rails - 4日目

P.57まで。
Controllerのテスト。
特に難しい点はなし。もっと纏められそうだけど、後で纏めるのかな?

require 'rails_helper'

describe ContactsController, type: :controller do
  describe 'GET #index' do
    context 'with params[:letter]' do
      it 'populates an array of contacts starting with the letter' do
        smith = create(:contact, lastname: 'Smith')
        jones = create(:contact, lastname: 'Jones')
        get :index, letter: 'S'
        expect(assigns(:contacts)).to match_array([smith])
      end

      it 'renders the :index template' do
        get :index, letter: 'S'
        expect(response).to render_template :index
      end
    end

    context 'without params[:letter]' do
      it 'populates an array of all contacts' do
        smith = create(:contact, lastname: 'Smith')
        jones = create(:contact, lastname: 'Jones')
        get :index
        expect(assigns(:contacts)).to match_array([smith, jones])
      end

      it 'renders the :index template' do
        get :index
        expect(response).to render_template :index
      end
    end
  end

  describe 'GET #show' do
    it 'assigns the requested contact to @contact' do
      contact = create(:contact)
      get :show, id: contact
      expect(assigns(:contact)).to eq contact
    end

    it 'renders the :new template' do
      contact = create(:contact)
      get :show, id: contact
      expect(response).to render_template :show
    end
  end

  describe 'GET #new' do
    it 'assigns a new Contact to @contact' do
      get :new
      expect(assigns(:contact)).to be_a_new Contact
    end

    it 'renders the :new template' do
      get :new
      expect(response).to render_template :new
    end
  end

  describe 'GET #edit' do
    it 'assigns the requested contact to @contact' do
      contact = create(:contact)
      get :edit, id: contact
      expect(assigns(:contact)).to eq contact
    end

    it 'renders the :edit template' do
      contact = create(:contact)
      get :edit, id: contact
      expect(response).to render_template :edit
    end
  end

  describe 'POST #create' do
    before do
      @phones = [
        attributes_for(:phone),
        attributes_for(:phone),
        attributes_for(:phone),
      ]
    end

    context 'with valid attributes' do
      it 'save the new contact in the database' do
        expect {
          post :create,
            contact: attributes_for(:contact, phones_attributes: @phones)
        }.to change(Contact, :count).by(1)
      end

      it 'redirects to contacts#show' do
        post :create,
          contact: attributes_for(:contact, phones_attributes: @phones)
        expect(response).to redirect_to contact_url(assigns(:contact))
      end
    end

    context 'with invalid attributes' do
      it 'dose not save the new contact in the database' do
        expect {
          post :create, contact: attributes_for(:invalid_contact)
        }.not_to change(Contact, :count)
      end

      it 're-renders the :new template' do
        post :create, contact: attributes_for(:invalid_contact)
        expect(response).to render_template :new
      end
    end
  end

  describe 'PATCH #update' do
    before do
      @firstname = 'Larry'
      @lastname = 'Smith'
      @contact = create(:contact, firstname: @firstname, lastname: @lastname)
    end

    context 'with valid attributes' do
      it 'updates the contact in the database' do
        patch :update, id: @contact, contact: attributes_for(:contact)
        expect(assigns(:contact)).to eq @contact
      end

      it "changes @contact's attribetus" do
        firstname = 'Larry'
        lastname  = 'Wall'
        patch :update, id: @contact,
          contact: attributes_for(
            :contact, firstname: firstname, lastname: lastname
          )
        @contact.reload
        expect(@contact.firstname).to eq firstname
        expect(@contact.lastname).to eq lastname
      end

      it 'redirects to the contact' do
        patch :update, id: @contact, contact: attributes_for(:contact)
        expect(response).to redirect_to @contact
      end
    end

    context 'with invalid attributes' do
      it 'dose not update the contact' do
        firstname = 'David'
        patch :update, id: @contact,
          contact: attributes_for(:contact, firstname: firstname, lastname: nil)
        @contact.reload
        expect(@contact.firstname).not_to eq firstname
        expect(@contact.lastname).to eq @lastname
      end

      it 're-renders the :edit template' do
        patch :update, id: @contact, contact: attributes_for(:invalid_contact)
        expect(response).to render_template :edit
      end
    end
  end

  describe 'DELETE #destroy' do
    before do
      @contact = create(:contact)
    end

    it 'deletes the contact from the database' do
      expect {
        delete :destroy, id: @contact
      }.to change(Contact, :count).by(-1)
    end

    it 'redirects to contacts#index' do
      delete :destroy, id: @contact
      expect(response).to redirect_to contacts_url
    end
  end
end

f:id:yossk:20141205234821j:plain

今日の感想

テストをどこまで書くか、というのは議論になりそうだ。
細かいレベルまで書いた方が、自分の凡ミスも防げそうで楽そう。
品質を担保するためじゃなく、プログラマ自身のためのテスト、か。