Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I test the assignment of an instance variable in the new action of my controller with rspec?

I am fairly new to testing and have a UsersController that I want to test. I am starting with the new action and so far have the following;

require 'spec_helper'

describe UsersController do

  describe "GET 'new'" do
    it "assigns a new User to @user" do
      user = User.new
      get :new
      assigns(:user).should eq(user)
    end
    it "renders the :new template"
  end

end

My UsersController so far looks like this

class UsersController < ApplicationController
  def new
    @user = User.new
  end
end

I expected my first test to work but when I run it I get the following;

Failures:

  1) UsersController GET 'new' assigns a new User to @user
     Failure/Error: assigns(:user).should eq(user)

       expected: #<User id: nil, email: nil, username: nil, password_digest: nil, created_at: nil, updated_at: nil>
            got: #<User id: nil, email: nil, username: nil, password_digest: nil, created_at: nil, updated_at: nil>

       (compared using ==)

       Diff:#<User:0x007fe4bbfceed0>.==(#<User:0x007fe4bce5c290>) returned false even though the diff between #<User:0x007fe4bbfceed0> and #<User:0x007fe4bce5c290> is empty. Check the implementation of #<User:0x007fe4bbfceed0>.==.
     # ./spec/controllers/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'

Playing around in the console reveals the following;

irb(main):001:0> a = User.new
=> #<User id: nil, email: nil, username: nil, password_digest: nil, created_at: nil, updated_at: nil>
irb(main):002:0> b = User.new
=> #<User id: nil, email: nil, username: nil, password_digest: nil, created_at: nil, updated_at: nil>
irb(main):003:0> a == b
=> false

So now I'm curious as to why 2 empty ActiveRecord objects are not equal (after all, Array.new == Array.new returns true), and what I have to do to make my test pass.

like image 837
brad Avatar asked Jun 03 '12 13:06

brad


2 Answers

You should probably change your test to something like this:

describe UsersController do

  describe "GET 'new'" do
    it "assigns a new User to @user" do
      get :new
      assigns(:user).should be_new_record
      assigns(:user).kind_of?(User).should be_true
    end
    it "renders the :new template"   end

end

And you will have the same effect. If two objects aren't saved, they don't have primary keys to Rails is going to use object_id equality to compare them, that's why they're not ==.

like image 184
Maurício Linhares Avatar answered Oct 02 '22 10:10

Maurício Linhares


Activerecord equality is largely about whether the two objects correspond to the same database row (for example two instances corresponding to the same row are equal, even of you start changing the attributes of one of them).

If you call User.new twice and saved each object you would end up with 2 distinct rows in the database. To me it therefore makes sense that they shouldn't be equal.

In terms of your test you could do 2 things. One is to check that the assigned user is a user and that it is unsaved.

Another way is something along the lines of

User.should_receive(:new).and_return(@user)
get :new
assigns(:user).should == @user
like image 20
Frederick Cheung Avatar answered Oct 02 '22 12:10

Frederick Cheung