Search code examples
ruby-on-railsrubyrspecrspec-rails

Test controller method. Rspec


I want to test the controller method, but I can not find the example of testing method with order and search . This is my controller:

class Admin::HotelsController < Admin::BaseController
  helper_method :sort_column, :sort_direction
  def index
    @hotels = Hotel.search(params[:search], params[:search_column]).order(sort_column + ' ' + sort_direction)
  end

  def show
    @hotel = Hotel.find(params[:id])

  end

  def update
    @hotel = Hotel.find(params[:id])
    if @hotel.update_attributes(hotel_params)
      redirect_to admin_hotels_path
    else
      render(:edit)
    end
  end

private
  def hotel_params
    params.require(:hotel).permit(:title, :description, :user_id, :avatar, :price, :breakfast, :status, address_attributes: [:state, :country, :city, :street])
  end

  def sort_column
    Hotel.column_names.include?(params[:sort]) ? params[:sort] : 'created_at'
  end

  def sort_direction
    %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
  end
end 

This is test for this controller.

require 'rails_helper'

describe Admin::HotelsController do
    login_admin
    describe 'GET index' do
        it 'render a list of hotels' do
            hotel1, hotel2 = create(:hotel), create(:hotel)
            get :index
            expect(assigns(:hotels)).to match_array([hotel1, hotel2])
        end
    end

  describe 'GET show' do
    it 'should show hotel' do
      @hotel = create(:hotel)
      get :show, { id: @hotel.to_param, template: 'hotels/show' }
      expect(response).to render_template :show
    end
  end


end

I don't know how testing index method. Please help or give me a link with information about this. Thanks!


Solution

  • If it may help you, I personally prefer to have minimals tests for the controllers for various reasons:

    1) as I was beginning in rails testing I read many articles saying it's a good idea 2) it allows you to tests in isolation model methods:

    describe 'GET index' do
      it 'render a list of hotels' do
        hotel1, hotel2 = create(:hotel), create(:hotel)
        get :index
        expect(assigns(:hotels)).to match_array([hotel1, hotel2])
      end
    end 
    

    here your test matches the result of your query on the model. You can split it like this:

    describe 'GET index' do
      it 'render a list of hotels' do
        hotel1, hotel2 = create(:hotel), create(:hotel)
        Hotel.should_receive(:search).with(YOUR PARAMS)
        get :index
        response.response_code.should == 200
      end
    end
    

    and then test the result of Hotel.search in a model test.

    3) it allows you to test the feature and not some random things that are not really relevant:

    describe 'GET show' do
      it 'should show hotel' do
        @hotel = create(:hotel)
        get :show, { id: @hotel.to_param, template: 'hotels/show' }
        expect(response).to render_template :show
      end
    end
    

    here "expect(response).to render_template :show" seems like testing that rails rendering system is properly working. I assume that's not what you want to test, you may prefer (that's what I would do):

    describe 'GET show' do
      it 'should show hotel' do
        @hotel = create(:hotel)
        Hotel.should_receive(:find).with(YOUR PARAMS)
        get :show, { id: @hotel.to_param, template: 'hotels/show' }
        response.response_code.should == 200
      end
    end
    

    and then test what is supposed to appear on the web page with a feature test using something like capybara gem unless you're rendering some json: in this case match the json values in the controller.

    By the way: "@hotel = create(:hotel)" the @ is not necessary here as you're in the "it". Moreover you can create such entry like this:

    context "" do
      before(:each) do
        @hotel = create(:hotel)   # here the @ is necessary for the variable to be        
        end                       # accessible in the it
      it "" do
      end
    end
    

    or even like this:

    context "" do
      let(:hotel) { create(:hotel) } # you can call it in the test by using hotel and it
      it "" do                       # will be insert in you db only when it's in the "it"
      end                            # if you want it to be created in the "it" without
    end                              # calling hotel for nothing, use let!