C.J. Bordeleau
C.J. Bordeleau

Reputation: 307

Rspec spec failing on update action

I have the following request spec

it "updates an open time" do
  # Create an OpenTime
  open_time = OpenTime.create(:start_time => (Time.now + 2.hours), :end_time => (Time.now + 10.hours))
  # Build an open_time update param
  params = {:open_time => {:start_time => (Time.now + 5.hours)}}
  # Send param to open_times#update
  put open_time_path(open_time.id) , params
  # Check to see if OpenTime was updated
  open_time.should_receive(:update_attributes).with({:start_time => (Time.now + 5.hours)})
end

Here is my open_times controller

def update
  @open_time = OpenTime.find(params[:id])
  if @open_time.update_attributes(params[:open_time])
    flash[:success] = "Time updated."
    redirect_to @open_time
  else
    render 'edit'
  end
end 

Test is failing with expected : 1 received: 0

Upvotes: 1

Views: 128

Answers (2)

Kocur4d
Kocur4d

Reputation: 6931

As kr1 noticed you have to stub OpenTime.find method to return your instance of OpenTime when it gets called from the controller. Change your test code to:

it "updates an open time" do
  target_time = (Time.now + 5.hours)
  # Create an OpenTime
  open_time = OpenTime.create(:start_time => (Time.now + 2.hours), :end_time => (Time.now + 10.hours))

  # Build an open_time update param
  params = {:open_time => {:start_time => target_time}}

  # Stub OpenTime to return your instance
  OpenTime.stub(:find).and_return(open_time)

  # Set expectation on open_time to receive :update_attributes
  open_time.should_receive(:update_attributes).with({:start_time => target_time})

  # Send param to open_times#update
  put open_time_path(open_time.id) , params
end

What is happening here is that you build your instance of OpenTime(open_time) and by stubbing OpenTime class you are saying "if someone call find on OpenTime class don't run find but simply return open_time(instance you just created)". Then you set up expectation on your instance to receive :update_attributes. When you call put open_time_path(open_time.id) , params your controller create action will process request and OpenTime.find(...) will return your instance(open_time) and call :update_attribute on it.

Hope it make a sense.

Upvotes: 1

kr1
kr1

Reputation: 7485

it is not that object that will receive update_attributes, but a new object returned by OpenTime.find, therefore, you should make sure that find returns your object:

OpenTime.stub(:find).and_return(open_time)
open_time.should_receive(:update_attributes).with({:start_time => (Time.now + 5.hours)})

and then:

put open_time_path(open_time.id) , params

additionaly, I would add target_time = Time.now + 5.hours at the beginning of the test, and then use that time in params and matcher.

Upvotes: 1

Related Questions