Search code examples
ruby-on-railsrubyrspecrspec-rails

Rspec - RuntimeError: Called id for nil, which would mistakenly be 4


I'm now making Rspec test for create action of ItemsController, however I'm in trouble about the error. (There are models as Item, Auction, Bid, User)

The create method is as follow

 # POST /items
 # POST /items.json
 def create
   @item = Item.new(params[:item])
   @item.user_id = current_user.id

   respond_to do |format|
     if @item.save
       format.html { redirect_to @item, notice: 'Item was successfully created.' }
       format.json { render json: @item, status: :created, location: @item }
     else
       format.html { render action: "new" }
       format.json { render json: @item.errors, status: :unprocessable_entity }
     end
   end
   @elapsed_seconds =(((params[:item][:days].to_i * 24)+params[:item][:hours].to_i)*60+params[:item][:minutes].to_i)*60
   @auction = Auction.create(:item_id => @item.id, :highest_bid_id => 0, :exp_time =>             
   @item.created_at+ @elapsed_seconds.seconds, :suspend => 0, :user_id => @current_user.id, :extend_bit => 0 )
   @item.update_attributes(:auction_id => @auction.id)
   @item_id = @item.id
   @auction_id = @auction.id
   @t1 = Thread.new{
     @timer = Timers.new
     @bid_timer = @timer.after(@elapsed_seconds){
       if Auction.find_by_id(@auction_id).suspend != 1
          buy
       end
     }
   @timer.wait
   }

end

def buy
  if Auction.find_by_id(@auction_id).extend_bit == 1
    extendtimer
  else
    if Auction.find_by_id(@auction_id).highest_bid_id != 0
      Item.find_by_auction_id(@auction_id).update_attributes(:sold => 1, :sold_to => Bid.find_by_id(Auction.find_by_id(@auction_id).highest_bid_id).user_id )
      MyMailer.auction_winner_email(Auction.find_by_id(@auction_id)).deliver
    else
      Item.find_by_auction_id(@auction_id).update_attributes(:sold => 0, :sold_to => 0 )
      MyMailer.no_bids_email(Auction.find_by_id(@auction_id)).deliver
    end
    @t1.join
  end
end

def extendtimer
    Auction.find_by_id(@auction_id).update_attributes(:extend_bit => 0)
    @exp = Auction.find_by_id(@auction_id).exp_time + 2.minutes
    Auction.find_by_id(@auction_id).update_attributes(:exp_time => @exp)
    @min = Item.find_by_id(@item_id).minutes + 2
    Item.find_by_id(@item_id).update_attributes(:minutes => @min)
    @timer2 = Timers.new
    @extend_timer = @timer2.after(120){ buy }
    @timer2.wait
end

And my Rspec is as follow. This test intends that at first objects were made to use (such as current_user, auction, "item). Then also stubs are declared. (such asAuction.stub(:find_by_id).and_return(auction)`)

require 'spec_helper'

describe ItemsController do

  let(:valid_session) { {} }

  describe "POST create" do
    it "" do
      #declare the objects and stubs
      current_user = User.new(id:'1')
      current_user.save
      auction = Auction.new(id:'1',highest_bid_id:'1', extend_bit:'1')
      auction.save
      Auction.stub(:find_by_id).and_return(auction)
      bid = Bid.new(auction_id:'1',amount:'150.0')
      bid.save
      Bid.stub(:find_by_id).and_return(bid)
      item = Item.new(id:'1',auction_id:'1',min_bid_price:'100.0')
      item.save
      Item.stub(:find_by_id).and_return(item)

      #POST create 
      post :create, {:item => {'id' => '2','days'=>'1','hours'=>'1','minutes'=>'1'}}

      response.should redirect_to(@item)
      flash[:notice].should eql("Item was successfully created.")


    end
  end
end

Unfortunately I ran Rspec, I got the error as follow. I think @item in controller could not be successfully created by @item = Item.new(params[:item]), so this error might be happen. However I couldn't find how to fix. I already used many hours for this. I would like to have someone's help.

Failures:

1) ItemsController POST create
 Failure/Error: post :create, {:item => {'id' => '2','days'=>'1','hours'=>'1','minutes'=>'1'}}
 RuntimeError:
   Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
 # ./app/controllers/items_controller.rb:72:in `create'
 # ./spec/controllers/items_controller_spec.rb:19:in `block (3 levels) in <top (required)>'

 Finished in 0.637 seconds 1 example, 1 failure

 Failed examples:

  rspec ./spec/controllers/items_controller_spec.rb:11 # ItemsController POST create

  Randomized with seed 33483  

Solution

  • Since no one is logged in, current_user method returns nil. Setting local variable current_user in spec won't help for that. Instead, you could define ApplicationController#current_user= method:

    def current_user=(user)
      @current_user ||= user
    end
    

    and call it in your specs:

    controller.current_user = current_user