Search code examples
ruby-on-railsrubyruby-on-rails-3rspecrspec-rails

Rspec error - NoMethodError: undefined method `empty?'


I'm now making Rspec for controller SearchController. This controller do search record by sql with parameter which was got by "get" request. The controller is as follow.

class SearchController < ApplicationController

  def index
    if params[:category] == 'All'
      @search_result = Item.find_by_sql("SELECT * FROM items WHERE name LIKE '%# {params[:name]}%'")
    else
      @search_result = Item.find_by_sql("SELECT * FROM items WHERE name LIKE '%#{params[:name]}%' AND category = '#{params[:category]}'")
    end
    if @search_result.empty? then
      redirect_to main_app.root_path, notice: "No items found matching your search criteria ! Modify your search."
    else
      @search_result=@search_result.paginate(:page => params[:page],:per_page => 3)
    end
  end
 end

Then I wrote simple Rspec test as follow. This test intends that at first the object item is made to use in controller. Also the stub (Item.stub(:find_by_sql).and_return(item)) is declared. Then do get :index with parameter :category => 'All'. My expect is that in the controller if params[:category] == 'All' is passed and @search_result is filled by object. (As I mentioned, the stub was already declared. Also object was already made. Then Item.find_by_sql(*****) would return object which was already declared.)

require 'spec_helper'

describe SearchController do

  let(:valid_session) { {} }

  describe "" do
     it "" do
      item = Item.new(auction_id:'1',min_bid_price:'100.0')
      item.save
      Item.stub(:find_by_sql).and_return(item)

      get :index, {:category => 'All'}, valid_session

      @search_result.should_not be_empty

     end
  end
end

Then I ran Rspec and unfortunately got the error as follow. I think @search_result could not be successfully filled with object, so "empty?" could not be called. However I have no idea about how to fix this. I already use many hours about this. I would like to have someone's help.

Failures:

  1) SearchController
     Failure/Error: get :index, {:category => 'All'}, valid_session
     NoMethodError:
     undefined method `empty?' for #<Item:0x523c980>
     # ./app/controllers/search_controller.rb:9:in `index'
     # ./spec/controllers/search_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

     Finished in 0.25 seconds
     1 example, 1 failure

  Failed examples:

     rspec ./spec/controllers/search_controller_spec.rb:8 # SearchController

     Randomized with seed 50151 

Solution

  • The problem is here:

    Item.stub(:find_by_sql).and_return(item)
    

    You are stubbing find_by_sql and returning a single item instead of a collection of items. The simple fix is to wrap it in an array:

    Item.stub(:find_by_sql).and_return [item]
    

    Note that this will only work if Array is modified to support paginate (will_paginate will do this if you require the `will_paginate/array' library).

    Aside from this, as @PeterAlfvin has mentioned, you have a mistake near the end of your spec:

    @search_result.should_not be_empty
    

    Should actually be written as:

    assigns(:search_result).should_not be_empty
    

    This is because you can't access instance variables assigned by your controller action directly.